2016-11-06 8 views
4

だから、私のモデルでは、私は選手クラスとゲームのクラスを持って、ゲームのようなので、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(); 
    } 
} 
+0

トリガは適切な解決策ではありません。これはEFレベルで解決できます。 (私は方法を知らない)あなたの削除コードを投稿してください。 – usr

+0

@usr削除コードを追加しました – Venser

+0

Playerオブジェクトのコレクションの1つのPlayer属性があります。コレクションが最低2つであることを検証します。あなたのためにそれを行うValidationAtttibuteがあるかどうか分かりませんが、簡単に作成できます。 –

答えて

1

Entity Frameworkコードを使用してゲームを手動で削除します。影響を受けるゲームに質問し、適切な削除方法(例:Entry(player).State = EntityState.Deletedのものまたは同等のもの)に渡します。

自動カスケードは手動では使用できません。

+0

プレイヤーを削除する前に削除方法を編集して削除しました。すべてが意図どおりに機能します。ありがとう! – Venser

0

あなたは両方のプレイヤーIDに[必須]属性を持っています。あなたが選手を削除しようとするとどうなりますか?おそらくイドのうちの1人がヌル可能であるべきですか?トリガーがあなたのための解決策ではないとのコメントに同意します。

+0

いずれかのプレイヤーを削除すると、質問の途中でエラーが発生します(「操作が失敗しました:関係.....」)、ゲームを削除することは問題なしです。 – Venser

関連する問題