如何在 EF Core 中使用连接 table 映射具有 "self-hierarchical" 关系的实体
How to map entity with "self-hierarchical" relationship using a join table in EF Core
我在使用现有数据库结构时遇到了一些问题,遗憾的是我无法更改。
我有以下 tables(为简单起见缩写)
CREATE TABLE EntityRelationship (
ChildID int,
ParentID int
)
CREATE TABLE Entity (
EntityID varchar,
EntityRelationshipID int
)
我将实体映射如下:
public class EntityRelationship {
[ForeignKey("Entity")]
public int ChildId { get; set; }
[ForeignKey("ParentEntity")]
public int ParentId { get; set; }
public Entity ParentEntity { get; set; }
public Entity Entity { get; set; }
}
public class Entity {
[Key]
public String EntityId { get; set; }
[ForeignKey("ParentEntity")]
public int EntityRelationshipId { get; set; }
public EntityRelationship ParentEntity { get; set; }
}
modelBuilder.Entity<EntityRelationship>()
.HasOne(c => c.ChildEntity)
.WithOne(c => c.ParentEntity);
我确保在加载时预先加载导航属性,但我仍然没有得到任何结果。
我假设它与我的映射有关,或者可能是因为带有连接 table 的数据库结构不是按照惯例使用一对一映射,它会触发整件事。
任何人都可以阐明这一点吗?
为了清楚起见,我希望能够做的是:
Entity parent = db.Entities.First().ParentEntity.Entity;
while (parent.ParentEntity.Entity != null) {
parent = parent.ParentEntity.Entity;
}
以便找到实体的最顶层父级。
使用此模型,link 实体 EntityRelationship
暗示 两个 FK 关系由 ChildId
和 ParentId
表示。对于这两种关系,link 实体是 dependent,主要实体 Entity
是 principal with EntityRelationshipId
作为主密钥。
所以基本上你需要正确映射这些两个关系的键和导航属性。删除 [ForeignKey]
数据注释以免乱七八糟
public class Entity
{
[Key]
public string EntityId { get; set; }
public int EntityRelationshipId { get; set; }
public EntityRelationship ParentEntity { get; set; }
}
public class EntityRelationship
{
public int ChildId { get; set; }
public int ParentId { get; set; }
public Entity ParentEntity { get; set; }
public Entity Entity { get; set; }
}
然后使用以下流畅的配置(它可以从另一侧配置,我选择 Entity
因为它看起来更自然地看到映射):
modelBuilder.Entity<Entity>(builder =>
{
// child => parent
builder.HasOne(e => e.ParentEntity)
.WithOne(r => r.Entity)
.HasForeignKey<EntityRelationship>(r => r.ChildId)
.HasPrincipalKey<Entity>(e => e.EntityRelationshipId);
// parent => children
builder.HasMany<EntityRelationship>()
.WithOne(r => r.ParentEntity)
.HasForeignKey(r => r.ParentId)
.HasPrincipalKey(e => e.EntityRelationshipId);
});
我在使用现有数据库结构时遇到了一些问题,遗憾的是我无法更改。
我有以下 tables(为简单起见缩写)
CREATE TABLE EntityRelationship (
ChildID int,
ParentID int
)
CREATE TABLE Entity (
EntityID varchar,
EntityRelationshipID int
)
我将实体映射如下:
public class EntityRelationship {
[ForeignKey("Entity")]
public int ChildId { get; set; }
[ForeignKey("ParentEntity")]
public int ParentId { get; set; }
public Entity ParentEntity { get; set; }
public Entity Entity { get; set; }
}
public class Entity {
[Key]
public String EntityId { get; set; }
[ForeignKey("ParentEntity")]
public int EntityRelationshipId { get; set; }
public EntityRelationship ParentEntity { get; set; }
}
modelBuilder.Entity<EntityRelationship>()
.HasOne(c => c.ChildEntity)
.WithOne(c => c.ParentEntity);
我确保在加载时预先加载导航属性,但我仍然没有得到任何结果。
我假设它与我的映射有关,或者可能是因为带有连接 table 的数据库结构不是按照惯例使用一对一映射,它会触发整件事。
任何人都可以阐明这一点吗?
为了清楚起见,我希望能够做的是:
Entity parent = db.Entities.First().ParentEntity.Entity;
while (parent.ParentEntity.Entity != null) {
parent = parent.ParentEntity.Entity;
}
以便找到实体的最顶层父级。
使用此模型,link 实体 EntityRelationship
暗示 两个 FK 关系由 ChildId
和 ParentId
表示。对于这两种关系,link 实体是 dependent,主要实体 Entity
是 principal with EntityRelationshipId
作为主密钥。
所以基本上你需要正确映射这些两个关系的键和导航属性。删除 [ForeignKey]
数据注释以免乱七八糟
public class Entity
{
[Key]
public string EntityId { get; set; }
public int EntityRelationshipId { get; set; }
public EntityRelationship ParentEntity { get; set; }
}
public class EntityRelationship
{
public int ChildId { get; set; }
public int ParentId { get; set; }
public Entity ParentEntity { get; set; }
public Entity Entity { get; set; }
}
然后使用以下流畅的配置(它可以从另一侧配置,我选择 Entity
因为它看起来更自然地看到映射):
modelBuilder.Entity<Entity>(builder =>
{
// child => parent
builder.HasOne(e => e.ParentEntity)
.WithOne(r => r.Entity)
.HasForeignKey<EntityRelationship>(r => r.ChildId)
.HasPrincipalKey<Entity>(e => e.EntityRelationshipId);
// parent => children
builder.HasMany<EntityRelationship>()
.WithOne(r => r.ParentEntity)
.HasForeignKey(r => r.ParentId)
.HasPrincipalKey(e => e.EntityRelationshipId);
});