EF Core 多对多自连接 [英] EF Core Many-to-Many self join

查看:28
本文介绍了EF Core 多对多自连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to describe a many-to-many self-referential relationship to Entity Framework Core 2. Essentially what I'm trying to model is a sort of tree structure, in which each element can have an arbitrary number of parent and child elements (so I guess more a graph than a tree). Here's what I have so far:

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

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

When i try to generate the initial migration, i get the following:

无法将导航属性ChildOrgLevel"添加到实体类型OrgLevelOrgLevels",因为实体类型OrgLevelOrgLevels"上已存在同名属性.

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

I am assuming this means that for the join table, it's trying to name both columns the same thing as they reference the same table.

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

Additionally, I don't really have any idea how to wire the last two navigation properties in the OrgLevel model so that they will use the join table to resolve.

任何帮助将不胜感激!

推荐答案

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

The main issue is the following fluent configuration:

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

错误信息有点误导.此重载需要 原始 属性(显式或 shadow),但您正在传递导航属性.

The error message is kind of misleading. This overload expects primitive properties (either explicit or shadow), but you are passing navigation properties.

有几种解决方法.

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

First, add explicit FK properties to the model (assuming referenced PK property type is 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 重载并在定义它们之后传递阴影属性名称:

Another way is to keep the model as is, but use another HasKey overload and pass shadow property names after they are defined:

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");

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

Of course you can define them explicitly in advance:

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

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

Note that this model introduces multiple cascade paths, so you need to turn cascade delete off at least of one of the two relationships and handle it manually.

这篇关于EF Core 多对多自连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆