我刚刚开始使用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个外键到同一个表?


当前回答

这是因为级联删除默认启用。问题是,当您对实体调用delete时,它也会删除每个f键引用的实体。你不应该让'required'值为空来解决这个问题。一个更好的选择是删除EF Code First的Cascade删除约定:

modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); 

在映射/配置时,显式地指示何时对每个子节点执行级联删除可能更安全。的实体。

其他回答

EF Core中的InverseProperty使解决方案简单而干净。

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; }
}

我知道这是一个几年前的帖子,你可以用上面的解决方案解决你的问题。然而,我只是想建议那些仍然需要使用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: https://msdn.microsoft.com/en-us/data/jj591583?f=255&MSPPError=-2147217396#Relationships上阅读更多关于InverseProperty的信息

这是因为级联删除默认启用。问题是,当您对实体调用delete时,它也会删除每个f键引用的实体。你不应该让'required'值为空来解决这个问题。一个更好的选择是删除EF Code First的Cascade删除约定:

modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); 

在映射/配置时,显式地指示何时对每个子节点执行级联删除可能更安全。的实体。

也可以在导航属性上指定ForeignKey()属性:

[ForeignKey("HomeTeamID")]
public virtual Team HomeTeam { get; set; }
[ForeignKey("GuestTeamID")]
public virtual Team GuestTeam { get; set; }

这样就不需要向OnModelCreate方法添加任何代码

你也可以试试这个:

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模式生成器。

在我的情况下,这个简单的修改解决了问题。