同一主键上的EF多个外键关系
Posted
技术标签:
【中文标题】同一主键上的EF多个外键关系【英文标题】:EF multiple foreign key relationship on same primary key 【发布时间】:2015-07-16 12:18:36 【问题描述】:我想使用 EF 6 使用代码优先方法创建多对多关系。我的实体使用复合主键(处理多租户)。
让我们举一个简单而经典的例子。我有两个实体Project
和Person
,它们具有多对多关系:
public class Person
[Key, Column(Order = 1),]
public Int32 Id get; set;
[Key, Column(Order = 2)]
public int TenantId get; set;
public string Name get; set;
public class Project
[Key, Column(Order = 1),]
public Int32 Id get; set;
[Key, Column(Order = 2)]
public int TenantId get; set;
Public string Name get; set;
我也有一个像这样的连接表ProjectPerson
:
上面我已经定义了Project
到ProjectPerson
的关系。请注意,公共类 ProjectPerson
[键,列(顺序 = 1),]
公共 Int32 Id 获取;放;
[键,列(顺序 = 2)]
[外键(“项目”)]
公共 int TenantId 获取;放;
[ForeignKey("Project")]
public int ProjectId get; set;
public DateTime AddedDate get; set;
public virtual Project Project get; set;
TenantId
用作主键和外键的一部分。
到目前为止,该模型按预期工作。但是缺少Person
到ProjectPerson
的关系。
我在ProjectPerson
类中添加了以下两行
[ForeignKey("Person")]
public int PersonId get; set;
public virtual Person Person get; set;
缺少到TenantId
的绝对映射。不知道怎么定义
更新
我找到了这个。但我仍然不满意,因为有额外的 TenantId (PersonTenantId
) 作为外键。
public class ProjectPerson
[Key, Column(Order = 1),]
public Int32 Id get; set;
[Key, Column(Order = 2)]
[ForeignKey("Project")]
public int TenantId get; set;
[ForeignKey("Project")]
public int ProjectId get; set;
[ForeignKey("Person")]
public int PersonId get; set;
[ForeignKey("Person")]
public int PersonTenantId get; set; // duplicate
public DateTime AddedDate get; set;
public virtual Project Project get; set;
public virtual Person Person get; set;
【问题讨论】:
为什么在 ProjectPerson 中需要 TenantId 映射,您已经在 project 和 person 表中都有映射?就 ProjectPerson 而言,TenantID 无关紧要。它只是一个关联表,给定的租户只能查询其租户中的项目或人员,对吗?您不需要此 TenancyID 成为此表的一部分,如果您尝试强制它,最终会得到 3 个表连接。除此之外,看看这个febdev.wordpress.com/2013/01/30/… @rism 两个原因: 1. ProjectPerson 中没有 TenantId,我们无法在 DBMS 中创建外键关联。 2. 租户数据应该能够在数据库之间移动。即每条记录都应该是唯一的。 我按照febdev.wordpress.com/2013/01/30/… 的说明进行操作,但出现以下错误Insufficient mapping: Foreign key must be mapped to some AssociationSet or EntitySets participating in a foreign key association on the conceptual side.
您是说您已经设置了密钥,以便租户A 可以拥有 ID = 1 的人员,而租户B 也可以拥有 ID = 1 的不同人员记录?
完全可以。特别是在以下情况。成像 TenantA 和 TenantB 在 DB X 中,而 TenantC 在 DB Y 中。后来 TenantB 移动了 DB Y
【参考方案1】:
使用 fluent API 为联结表中的两个 FK 重用 TentantId
列。 ProjectId
也应该包含在联结表的 PK 中。请注意,我修改了复合主键列的顺序,将TenantId
作为第一列。
public class Person
[Key, Column(Order = 0)]
public int TenantId get; set;
[Key, Column(Order = 1)]
public int PersonId get; set;
public string Name get; set;
public virtual ICollection<ProjectPerson> ProjectPeople get; set;
public class Project
[Key, Column(Order = 0)]
public int TenantId get; set;
[Key, Column( Order = 1 )]
public int ProjectId get; set;
public string Name get; set;
public virtual ICollection<ProjectPerson> ProjectPeople get; set;
public class ProjectPerson
[Key, Column( Order = 0 )]
public int TentantId get; set;
[Key, Column( Order = 1 )]
public int ProjectId get; set;
[Key, Column( Order = 2 )]
public int PersonId get; set;
public DateTime AddedDate get; set;
public virtual Project Project get; set;
public virtual Person Person get; set;
protected override void OnModelCreating( DbModelBuilder modelBuilder )
base.OnModelCreating( modelBuilder );
modelBuilder.Entity<Project>()
.HasMany(pr => pr.ProjectPeople )
.WithRequired( pp => pp.Project )
.HasForeignKey( pp => new pp.TentantId, pp.ProjectId );
modelBuilder.Entity<Person>()
.HasMany( pe => pe.ProjectPeople )
.WithRequired( pp => pp.Person )
.HasForeignKey( pp => new pp.TentantId, pp.PersonId );
【讨论】:
以上是关于同一主键上的EF多个外键关系的主要内容,如果未能解决你的问题,请参考以下文章