EFコードを最初に使い始めたばかりなので、このトピックの初心者です。
チームと試合の関係を作成したかった:1試合= 2チーム(ホーム、ゲスト)と結果。そのようなモデルを作成するのは簡単だと思ったので、コーディングを始めました。
public class Team
{
[Key]
public int TeamId { get; set;}
public string Name { get; set; }
public virtual ICollection<Match> Matches { get; set; }
}
public class Match
{
[Key]
public int MatchId { get; set; }
[ForeignKey("HomeTeam"), Column(Order = 0)]
public int HomeTeamId { get; set; }
[ForeignKey("GuestTeam"), Column(Order = 1)]
public int GuestTeamId { get; set; }
public float HomePoints { get; set; }
public float GuestPoints { get; set; }
public DateTime Date { get; set; }
public virtual Team HomeTeam { get; set; }
public virtual Team GuestTeam { get; set; }
}
そして、私は例外を取得します:
参照関係により、循環参照が許可されなくなります。 [制約名= Match_GuestTeam]
同じテーブルに2つの外部キーを使用して、このようなモデルを作成するにはどうすればよいですか? TIA。
これを試して:
public class Team
{
public int TeamId { get; set;}
public string Name { get; set; }
public virtual ICollection<Match> HomeMatches { get; set; }
public virtual ICollection<Match> AwayMatches { get; set; }
}
public class Match
{
public int MatchId { get; set; }
public int HomeTeamId { get; set; }
public int GuestTeamId { get; set; }
public float HomePoints { get; set; }
public float GuestPoints { get; set; }
public DateTime Date { get; set; }
public virtual Team HomeTeam { get; set; }
public virtual Team GuestTeam { get; set; }
}
public class Context : DbContext
{
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Match>()
.HasRequired(m => m.HomeTeam)
.WithMany(t => t.HomeMatches)
.HasForeignKey(m => m.HomeTeamId)
.WillCascadeOnDelete(false);
modelBuilder.Entity<Match>()
.HasRequired(m => m.GuestTeam)
.WithMany(t => t.AwayMatches)
.HasForeignKey(m => m.GuestTeamId)
.WillCascadeOnDelete(false);
}
}
主キーはデフォルトの規則でマッピングされます。チームには2つのマッチのコレクションが必要です。 2つのFKによって参照される単一のコレクションを持つことはできません。これらの自己参照多対多では機能しないため、カスケード削除を使用せずに一致がマップされます。
ナビゲーションプロパティでForeignKey()
属性を指定することもできます。
[ForeignKey("HomeTeamID")]
public virtual Team HomeTeam { get; set; }
[ForeignKey("GuestTeamID")]
public virtual Team GuestTeam { get; set; }
そうすれば、OnModelCreate
メソッドにコードを追加する必要はありません
私はそれが数年前の投稿であることを知っており、上記の解決策で問題を解決することができます。ただし、まだ必要な人にはInversePropertyを使用することをお勧めします。少なくとも、OnModelCreatingで何も変更する必要はありません。
以下のコードはテストされていません。
public class Team
{
[Key]
public int TeamId { get; set;}
public string Name { get; set; }
[InverseProperty("HomeTeam")]
public virtual ICollection<Match> HomeMatches { get; set; }
[InverseProperty("GuestTeam")]
public virtual ICollection<Match> GuestMatches { get; set; }
}
public class Match
{
[Key]
public int MatchId { get; set; }
public float HomePoints { get; set; }
public float GuestPoints { get; set; }
public DateTime Date { get; set; }
public virtual Team HomeTeam { get; set; }
public virtual Team GuestTeam { get; set; }
}
InversePropertyの詳細については、MSDNをご覧ください: https://msdn.Microsoft.com/en-us/data/jj591583?f=255&MSPPError=-2147217396#Relationships
あなたもこれを試すことができます:
public class Match
{
[Key]
public int MatchId { get; set; }
[ForeignKey("HomeTeam"), Column(Order = 0)]
public int? HomeTeamId { get; set; }
[ForeignKey("GuestTeam"), Column(Order = 1)]
public int? GuestTeamId { get; set; }
public float HomePoints { get; set; }
public float GuestPoints { get; set; }
public DateTime Date { get; set; }
public virtual Team HomeTeam { get; set; }
public virtual Team GuestTeam { get; set; }
}
FK列でNULLを許可すると、サイクルが中断されます。または、EFスキーマジェネレーターをごまかしています。
私の場合、この簡単な変更で問題は解決します。
これは、カスケード削除がデフォルトで有効になっているためです。問題は、エンティティでdeleteを呼び出すと、fキーで参照される各エンティティも削除されることです。この問題を解決するために「必須」値をヌル可能にしないでください。より良いオプションは、EF Code Firstのカスケード削除規則を削除することです。
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
マッピング/構成時に、各子に対してカスケード削除をいつ行うかを明示的に示す方がおそらく安全です。エンティティ。
EF CoreのInverseProperty
は、ソリューションを簡単かつクリーンにします。
したがって、望ましい解決策は次のとおりです:
public class Team
{
[Key]
public int TeamId { get; set;}
public string Name { get; set; }
[InverseProperty(nameof(Match.HomeTeam))]
public ICollection<Match> HomeMatches{ get; set; }
[InverseProperty(nameof(Match.GuestTeam))]
public ICollection<Match> AwayMatches{ get; set; }
}
public class Match
{
[Key]
public int MatchId { get; set; }
[ForeignKey(nameof(HomeTeam)), Column(Order = 0)]
public int HomeTeamId { get; set; }
[ForeignKey(nameof(GuestTeam)), Column(Order = 1)]
public int GuestTeamId { get; set; }
public float HomePoints { get; set; }
public float GuestPoints { get; set; }
public DateTime Date { get; set; }
public Team HomeTeam { get; set; }
public Team GuestTeam { get; set; }
}