【问题标题】:EF Core Many-to-Many self joinEF Core 多对多自联接
【发布时间】:2018-06-21 03:15:42
【问题描述】:

我试图描述与 Entity Framework Core 2 的多对多自引用关系。本质上,我试图建模的是一种树结构,其中每个元素都可以有任意数量的父元素和子元素(所以我猜更多的是图表而不是树)。这是我目前所拥有的:

public class OrgLevel
{
    ...

    public ICollection<OrgLevelOrgLevels> OrgLevelOrgLevelsAsParent { get; set; }

    public ICollection<OrgLevelOrgLevels> OrgLevelOrgLevelsAsChild { get; set; }

    public ICollection<OrgLevel> ParentOrganizationStructureLevels { get; set; }

    public ICollection<OrgLevel> ChildOrganizationStructureLevels { get; set; }
}

public class OrgLevelOrgLevels
{
    public OrgLevel ParentOrgLevel { get; set; }
    public OrgLevel ChildOrgLevel { get; set; }
}

public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string>
{
    ...

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<OrgLevelOrgLevels>()
            .HasKey(t => new { t.ParentOrgLevel, t.ChildOrgLevel });

        builder.Entity<OrgLevelOrgLevels>().HasOne(olol => olol.ChildOrgLevel)
            .WithMany(col => col.OrgLevelOrgLevelsAsChild);

        builder.Entity<OrgLevelOrgLevels>().HasOne(olol => olol.ParentOrgLevel)
            .WithMany(pol => pol.OrgLevelOrgLevelsAsParent);
    }
}

当我尝试生成初始迁移时,我得到以下信息:

The navigation property 'ChildOrgLevel' cannot be added to the entity type 'OrgLevelOrgLevels' because a property with the same name already exists on entity type 'OrgLevelOrgLevels'.

我假设这意味着对于连接表,它试图将两个列命名为相同的东西,因为它们引用同一个表。

此外,我真的不知道如何连接OrgLevel 模型中的最后两个导航属性,以便它们使用连接表来解析。

任何帮助将不胜感激!

【问题讨论】:

  • ParentOrganizationStructureLevelsChildOrganizationStructureLevels 集合的目的是什么。它们不会导致您当前的问题,但会在您解决后导致其他问题。
  • 我在这里的意图是让这些表示连接表正在映射的实际实体。我希望能够通过连接表遍历关系并获取给定 OrgLevel 的子级或父级。也许这对于 EF Core 是不可能的。
  • 是的,这看起来像是多对多与显式联结表和隐式联结表的混合(EF Core 尚不支持)。如果支持,您可以使用其中一个,但不能同时使用。

标签: c# asp.net entity-framework .net-core entity-framework-core


【解决方案1】:

主要问题是以下流畅的配置:

builder.Entity<OrgLevelOrgLevels>()
    .HasKey(t => new { t.ParentOrgLevel, t.ChildOrgLevel });

错误信息有点误导。此重载需要原始属性(显式或shadow),但您传递的是navigation properties

有几种方法可以解决它。

首先,向模型添加显式 FK 属性(假设引用的 PK 属性类型为 int):

public class OrgLevelOrgLevels
{
    public int ParentOrgLevelId { get; set; }
    public OrgLevel ParentOrgLevel { get; set; }
    public int ChildOrgLevelId { get; set; }
    public OrgLevel ChildOrgLevel { get; set; }
}

并使用

builder.Entity<OrgLevelOrgLevels>()
    .HasKey(t => new { t.ParentOrgLevelId, t.ChildOrgLevelId });

另一种方法是保持模型不变,但使用另一个 HasKey 重载并在定义它们之后传递影子属性名称​​

builder.Entity<OrgLevelOrgLevels>().HasOne(olol => olol.ChildOrgLevel)
    .WithMany(col => col.OrgLevelOrgLevelsAsChild)
    .OnDelete(DeleteBehavior.Restrict);

builder.Entity<OrgLevelOrgLevels>().HasOne(olol => olol.ParentOrgLevel)
    .WithMany(pol => pol.OrgLevelOrgLevelsAsParent);

builder.Entity<OrgLevelOrgLevels>()
     .HasKey("ParentOrgLevelId", "ChildOrgLevelId");

当然你可以提前明确定义:

builder.Entity<OrgLevelOrgLevels>()
    .Property<int>("ParentOrgLevelId");

builder.Entity<OrgLevelOrgLevels>()
    .Property<int>("ChildOrgLevelId");

builder.Entity<OrgLevelOrgLevels>()
     .HasKey("ParentOrgLevelId", "ChildOrgLevelId");

builder.Entity<OrgLevelOrgLevels>().HasOne(olol => olol.ChildOrgLevel)
    .WithMany(col => col.OrgLevelOrgLevelsAsChild)
    .OnDelete(DeleteBehavior.Restrict);

builder.Entity<OrgLevelOrgLevels>().HasOne(olol => olol.ParentOrgLevel)
    .WithMany(pol => pol.OrgLevelOrgLevelsAsParent);

请注意,此模型引入了多个级联路径,因此您需要将级联删除至少关闭两个关系之一并手动处理。

【讨论】:

  • 这是有效的。感谢您提供有关级联行为的额外提示!
猜你喜欢
  • 2021-11-16
  • 2020-04-29
  • 1970-01-01
  • 1970-01-01
  • 2020-11-19
  • 2020-07-14
  • 1970-01-01
  • 2021-03-03
  • 1970-01-01
相关资源
最近更新 更多