我刚开始使用 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 个外键?
尝试这个:
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 引用的单个集合。匹配在没有级联删除的情况下进行映射,因为它在这些自引用多对多中不起作用。
还可以在导航属性上指定 ForeignKey()
属性:
[ForeignKey("HomeTeamID")]
public virtual Team HomeTeam { get; set; }
[ForeignKey("GuestTeamID")]
public virtual Team GuestTeam { get; set; }
这样您就无需向 OnModelCreate
方法添加任何代码
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
你也可以试试这个:
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 模式生成器。
就我而言,这个简单的修改解决了这个问题。
这是因为级联删除默认启用。问题是当您在实体上调用 delete 时,它也会删除每个 f-key 引用的实体。您不应将“必需”值设为可空来解决此问题。更好的选择是删除 EF Code First 的级联删除约定:
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
在映射/配置时明确指示何时对每个子级执行级联删除可能更安全。实体。
Restrict
而不是 Cascade
?
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 int? HomeTeamId { 获取;放; } 公共整数? GuestTeamId { 得到;放; } 公共浮动 HomePoints { 获取;放; } 公共浮动 GuestPoints { 获取;放; } 公共日期时间日期 { 获取;放; } 公共团队 HomeTeam { 获取;放; } 公共团队 GuestTeam { 获取;放; } } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity