EF核心多对多自我加入 [英] EF Core Many-to-Many self join
问题描述
我试图描述与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屋!