简体   繁体   English

EF核心多对多自我加入

[英]EF Core Many-to-Many self join

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). 我试图描述与Entity Framework Core 2的多对多自引用关系。本质上,我要建模的是一种树结构,其中每个元素可以具有任意数量的父元素和子元素(所以我猜想更多的是图形而不是树)。 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: 当我尝试生成初始迁移时,得到以下信息:

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'.

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. 我假设这意味着对于联接表,它试图为两列引用相同的表而命名。

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. 另外,我真的不知道如何在OrgLevel模型中连接最后两个导航属性,以便它们将使用OrgLevel表来进行解析。

Any help would be appreciated! 任何帮助,将不胜感激!

The main issue is the following fluent configuration: 主要问题是以下流畅的配置:

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

The error message is kind of misleading. 该错误消息有点误导。 This overload expects primitive properties (either explicit or shadow ), but you are passing navigation properties . 此重载需要原始属性(显式或阴影 ),但是您正在传递导航属性

There are several ways to resolve it. 有几种解决方法。

First, add explicit FK properties to the model (assuming referenced PK property type is int ): 首先,向模型添加显式的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; }
}

and use 和使用

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

Another way is to keep the model as is, but use another HasKey overload and pass shadow property names after they are defined: 另一种方法是保持模型不变,但使用另一个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");

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. 请注意,此模型引入了多个级联路径,因此您需要关闭级联删除,至少要关闭两个关系之一,然后手动进行处理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM