Entity Framework 多个外键指向同一个 table

Entity Framework multiple foreign keys to the same table

我有两个实体 DataTag 和 CalcDataTag:

public class CalcDataTag : BaseModel
{
    [Column("CalcDataTagId")]
    public override Guid ID { get; set; }

    public Guid DataTagId { get; set; }
    public DataTag DataTag { get; set; }

    public Guid ChildDataTagId { get; set; }
    public DataTag ChildDataTag { get; set; }
}

public class DataTag : BaseModel
{
    [Column("DataTagId")]
    public override Guid ID { get; set; }

    public ICollection<CalcDataTag> CalcDataTags { get; set; }
}

我这样设置上下文:

modelBuilder.Entity<DataTag>()
            .HasMany<CalcDataTag>(x => x.CalcDataTags)
            .WithRequired(x => x.ChildDataTag)
            .HasForeignKey(x => x.ChildDataTagId);

        modelBuilder.Entity<DataTag>()
            .HasMany<CalcDataTag>(x => x.CalcDataTags)
            .WithRequired(x => x.DataTag)
            .HasForeignKey(x => x.DataTagId);

CalcDataTags 列表应该是一个 CalcDataTags 列表,其中 DataTagId 或 ChildDataTagId 等于 DataTag 的 ID,但是上下文的设置方式,底部设置覆盖顶部设置,我只得到一个列表CalcDataTags,其中 DataTagId 等于 DataTag 的 ID。如果我切换设置,那么我只会得到一个 CalcDataTags 列表,其中 ChildCalcDataTagId 等于 DataTag 的 ID。基本上我想要得到的是两个列表的联合。每个实体只有一个主键,没有复合键。

您的 DataTag table 需要第二个 collection。没有其他办法解决它。 Entity Framework 越来越混乱,因为它只能将一个 one-to-many 关系映射到特定的 属性,而不是两个。您需要执行以下操作:

DataTag中:

public ICollection<CalcDataTag> CalcDataTags { get; set; }
public ICollection<CalcDataTag> ChildCalcDataTags { get; set; }

在你的modelBuilder中:

modelBuilder.Entity<DataTag>()
            .HasMany<CalcDataTag>(x => x.ChildCalcDataTags)
            .WithRequired(x => x.ChildDataTag)
            .HasForeignKey(x => x.ChildDataTagId);

modelBuilder.Entity<DataTag>()
            .HasMany<CalcDataTag>(x => x.CalcDataTags)
            .WithRequired(x => x.DataTag)
            .HasForeignKey(x => x.DataTagId);

如果您希望能够同时抓取所有这些(就像您所做的那样),您可能需要考虑添加一个 [NotMapped] 属性 来抓取两个 collection 的并集,如下所示:

[NotMapped]
public ICollection<CalcDataTag> AllCalcDataTags
{
  return CalcDataTags.Union(ChildCalcDataTags);
}