EF核心多对多自我加入 [英] EF Core Many-to-Many self join

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

问题描述

我试图描述与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 });

该错误消息有点误导.此重载期望 primitive 属性(显式或阴影),但您正在传递导航属性.

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核心多对多自我加入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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