实体框架代码优先:在具有不同连接列的实体中展平组合

Posted

技术标签:

【中文标题】实体框架代码优先:在具有不同连接列的实体中展平组合【英文标题】:Entity Framework Code First : flatten composition in entity with different join column 【发布时间】:2016-10-23 05:12:40 【问题描述】:

我在使用 Code First 配置使用 EntityFramework 时遇到问题。 我有两张桌子:

+---------------+        +-------------+
|  T_CONTRACTS  |        |  T_PERSONS  |
|---------------|        |-------------|
|CONTRACT_ID    |        |PERSON_ID    |
|CUSTOMER_ID    |        |NAME         |
+---------------+        +-------------+

我想要一个 EF 实体:

public class Contract

    public int ContractId  get; set; 
    public int CustomerId  get; set; 
    public string CustomerName  get; set; 


现在,我想将我的两个表映射到我的实体上。我命令这样做,我使用了 EntityTypeConfiguration。

public class ContractConfiguration : EntityTypeConfiguration<Contract>

    public ContractConfiguration()
    
        ToTable("T_CONTRACTS", "ASSUROL"); //table and schema ALWAYS in uppercase
        HasKey(c => c.ContractId);
        Property(c => c.ContractId).HasColumnName("CONTRACT_ID").IsRequired();
        Property(c => c.CustomerId).HasColumnName("CUSTOMER_ID").IsRequired();

        // TODO : WIP, no idea of what i am doing
        HasRequired(c => c.CustomerName).WithRequiredPrincipal().Map( ca => 
            ca.MapKey("PERSON_ID");
            ca.ToTable("T_PERSONS", "ASSUROL");

            //Property(c => c.CustomerName).HasColumnName("NAME");
        );

    

废话来了,我不知道如何实现映射。

-如何将一个实体字段映射到两个表?

-如何连接两个具有不同列名的表作为外键(这里是CUSTOMER_ID和PERSON_ID)?

非常感谢,

PS:我知道我们可以通过创建两个带有数据注释的实体来做到这一点。我想避免数据注释(因为关注点分离),我想保留一个实体。

【问题讨论】:

【参考方案1】:

首先,您的模型看起来不正确。你(可能)想要这样的东西:

public class Contract

    public int ContractId  get; set; 
    public int PersonId  get; set; 
    public Person Customer  get; set;   // Use a navigation property to relate


public class Person

    public int PersonId  get; set; 
    public string Name  get; set; 
    public ICollection<Contract> Contracts  get; set;   // A person can have many contracts, no?

现在您可以将流利的代码更改为:

public class ContractConfiguration : EntityTypeConfiguration<Contract>

    public ContractConfiguration()
    
        ToTable("T_CONTRACTS", "ASSUROL"); //table and schema ALWAYS in uppercase
        HasKey(c => c.ContractId);  // Redundant since ContractId is key via convention
        Property(c => c.ContractId).HasColumnName("CONTRACT_ID").IsRequired();
        Property(c => c.PersonId).HasColumnName("CUSTOMER_ID").IsRequired();

        // Configure the relationship although EF should pick this up by convention as well...
        HasRequired(c => c.Customer).WithMany(p => p.Contracts);

    

现在您可以很容易地编写一个查询来“扁平化”关系:

context.Contracts.Select(c => new 
       c.ContractId,
       CustomerId = c.PersonId,
       CustomerName = c.Person.Name ).ToList();

编辑:重读后,我发现您可能需要的是表拆分,尽管第一种方法更好 IMO,因为您似乎正在尝试将 ViewModel 构建到您的实体模型中,这不是表的意图分裂。 IAC,如果你想要它,流畅的代码看起来类似于:

modelBuilder.Entity<Contract>() 
    .Map(m => 
     
        m.Properties(c => new  c.CustomerId, c.ContractId ); 
        m.ToTable("T_CONTRACTS"); 
    ) 
    .Map(m => 
     
        m.Properties(p => new  p.PersonID, p.Name ); 
        m.ToTable("T_PERSONS"); 
    );

https://msdn.microsoft.com/en-us/data/jj591617.aspx?f=255&MSPPError=-2147217396#2.7

【讨论】:

【参考方案2】:

非常感谢,感谢关键字“实体拆分”,我找到了其他帖子: Entity splitting when key column has different names? Entity framework map entity to multiple tables?

这是我的工作配置:

    public ContractConfiguration()
    
        HasKey(c => c.CustomerId);
        Map(m =>
        
            m.Property(c => c.ContractId).HasColumnName("CONTRACT_ID");
            m.Property(c => c.CustomerId).HasColumnName("CUSTOMER_ID");
            m.ToTable("T_CONTRACTS");
        );
        Map(m =>
        
            m.Property(cust => cust.CustomerId).HasColumnName("PERSON_ID");
            m.Property(cust => cust.CustomerName).HasColumnName("NAME");
            m.ToTable("T_PERSONS");
        );
    

【讨论】:

以上是关于实体框架代码优先:在具有不同连接列的实体中展平组合的主要内容,如果未能解决你的问题,请参考以下文章

最有效的实体框架代码第一方法展平/投影具有特定子实体的父实体

如何在实体框架代码优先方法中使用表值函数?

实体框架 4.1 代码优先映射到将主键作为外键列的表

EF6:代码优先复杂类型

代码优先实体框架或 NHibernate

如何将实体框架(代码优先)与动态创建的连接字符串和单文件数据库一起使用?