同一主键上的EF多个外键关系

Posted

技术标签:

【中文标题】同一主键上的EF多个外键关系【英文标题】:EF multiple foreign key relationship on same primary key 【发布时间】:2015-07-16 12:18:36 【问题描述】:

我想使用 EF 6 使用代码优先方法创建多对多关系。我的实体使用复合主键(处理多租户)。

让我们举一个简单而经典的例子。我有两个实体ProjectPerson,它们具有多对多关系:

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

上面我已经定义了ProjectProjectPerson 的关系。请注意,公共类 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 用作主键和外键的一部分。

到目前为止,该模型按预期工作。但是缺少PersonProjectPerson 的关系。

我在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多个外键关系的主要内容,如果未能解决你的问题,请参考以下文章

SQLAlchemy 一个映射类中的多个外键到同一个主键

通过在Oracle子表外键上建立索引提高性能

将外键上的 SQL 连接转换为 R data.table 语法

MS Access表与多个外键在同一表中的关系。

EF6(代码优先)单个外键属性上的多个导航属性

在多个外键上组合唯一键