[英]How to create a table with two foreign keys pointing to the same table using Entity Framework Code First
[英]Entity Framework Code First - two Foreign Keys from same table
我剛開始使用 EF 代碼,所以我完全是這個主題的初學者。
我想在 Teams 和 Matches 之間創建關系:
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 個外鍵?
試試這個:
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);
}
}
主鍵按默認約定映射。 團隊必須有兩個比賽集合。 您不能擁有兩個FK引用的單個集合。 匹配是在沒有級聯刪除的情況下映射的,因為它在這些自引用多對多中不起作用。
也可以在navigation屬性上指定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; }
}
您可以在MSDN上閱讀有關InverseProperty的更多信息: https ://msdn.microsoft.com/en-us/data/jj591583?f = 255 & MSPPError = -2147217396#Relationships
這是因為默認情況下啟用Cascade Deletes。 問題是,當您在實體上調用刪除時,它也會刪除每個f鍵引用的實體。 您不應該使“必需”值可以為空來解決此問題。 更好的選擇是刪除EF Code First的Cascade刪除約定:
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
在映射/配置時,明確指示何時為每個子節點執行級聯刪除可能更安全。 實體。
你也可以試試這個:
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列允許NULLS時,您正在打破循環。 或者我們只是在欺騙EF模式生成器。
就我而言,這個簡單的修改解決了這個問題。
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; }
}
我知道這是一個很老的問題,但在 2021 年來到這里,下面的 EF Core > 3 解決方案對我有用。
確保外鍵可以為空
指定刪除時的默認行為
public class Match { 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 Team HomeTeam { get; set; } public Team GuestTeam { get; set; } } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Match>() .HasRequired(m => m.HomeTeam) .WithMany(t => t.HomeMatches) .HasForeignKey(m => m.HomeTeamId) .OnDelete(DeleteBehavior.ClientSetNull); modelBuilder.Entity<Match>() .HasRequired(m => m.GuestTeam) .WithMany(t => t.AwayMatches) .HasForeignKey(m => m.GuestTeamId) .OnDelete(DeleteBehavior.ClientSetNull); }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.