だから、私のモデルでは、私は選手クラスとゲームのクラスを持って、ゲームのようなので、2人の必要なプレーヤーを持っています(いくつかの他のフィールドと一緒に、私はここに含まれていませんでした)MVCで2対1の関係を扱う方法は?
public class Game
{
public Player Player1 { get; set; }
[Required]
public int Player1Id { get; set; }
public Player Player2 { get; set; }
[Required]
public int Player2Id { get; set; }
}
移行しようとするとデータベースには、このモデルでは、私は次のエラーを取得する:
Introducing FOREIGN KEY constraint 'FK_dbo.Games_dbo.Players_Player2Id' on table 'Games' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
(。this stackoverflow questionへの答えは、私はこのエラーを取得する理由の良い説明を与える)
をこのエラーを回避するには、私は次の流暢を追加しましたAPIコード:
modelBuilder.Entity<Game>()
.HasRequired(c => c.Player1)
.WithMany()
.HasForeignKey(c => c.Player1Id)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Game>()
.HasRequired(c => c.Player2)
.WithMany()
.HasForeignKey(c => c.Player2Id)
.WillCascadeOnDelete(false);
しかし、今問題が発生するのは、IDが1つ以上のゲームで参照されているプレーヤーを削除しようとするときです。私はこのエラーを正しく理解していた場合、ゲームはプレイヤーと一緒に削除されませんので
The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.
は、私は、(カスケード削除偽であるため、障害が発生し、ゲームの外部キー制約の1つのこのエラーが発生します。代わりに、Player1Id(またはPlayer2Id)がnullに設定されているため、制約が破られます。なぜなら、両方とも必須であり、nullableでないからです)
Seed()メソッドのthis SO questionのようなトリガーを作成しようとしました。私は自分のデータベースをチェックすると
context.Database.ExecuteSqlCommand("CREATE TRIGGER Game_Player_Del on dbo.Players instead of delete as " +
"set nocount on " +
"delete from dbo.Games where Player1Id in (select Id from deleted) or " +
"Player2Id in (Select Id from deleted) " +
"delete from dbo.Players where Id in (select Id from deleted)");
、トリガが追加されますんが、私はまだトリガーを追加する前と同じエラーが出るように動作していないようです。
この作業を意図したものにするにはどうすればよいですか? (プレイヤーを削除すると関連するゲームも削除されますが、ゲームを削除してもプレーヤーは削除されません)
編集:私の考えでは、私のコントローラーのdeleteメソッドを編集して、 Player1IdまたはPlayer2IdはPlayer.Idと等しく、それらを削除してから削除しますが、(私は思うのですが)プレイヤーを削除するときにゲームについて心配する必要はありません。
編集2:(USRさんのコメントに反応して)ここに私の削除コードだ:
コントローラー:
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
repo.deletePlayer(id);
return RedirectToAction("Index");
}
レポ:
public void deletePlayer(int id)
{
using (var context = new TennisContext())
{
player = context.Players.Find(id);
context.Entry(player).State = EntityState.Deleted;
context.SaveChanges();
}
}
編集3:私はそれを動作させるために管理プレイヤーを削除する前に、影響を受けるゲームを照会および削除することによって、
レポコード:
public void deletePlayer(int id)
{
using (var context = new TennisContext())
{
player = context.Players.Find(id);
List<Game> playerGames = context.Games.Where(g => g.Player1Id == id || g.Player2Id == id).ToList();
foreach (Game g in playerGames)
{
context.Entry(g).State = EntityState.Deleted;
}
context.Entry(player).State = EntityState.Deleted;
context.SaveChanges();
}
}
トリガは適切な解決策ではありません。これはEFレベルで解決できます。 (私は方法を知らない)あなたの削除コードを投稿してください。 – usr
@usr削除コードを追加しました – Venser
Playerオブジェクトのコレクションの1つのPlayer属性があります。コレクションが最低2つであることを検証します。あなたのためにそれを行うValidationAtttibuteがあるかどうか分かりませんが、簡単に作成できます。 –