EF 代码第一个一对多(使用“通用”表)

Posted

技术标签:

【中文标题】EF 代码第一个一对多(使用“通用”表)【英文标题】:EF Code First One To Many (using a "common" table) 【发布时间】:2014-03-22 01:27:46 【问题描述】:

考虑以下示例:

一个人可以有多个地址。一个商店可以有多个地址。 两者都有一个 1:M 到地址表。

使用 EF6,Code First,我如何设置我的实体和映射 (FluentApi) 来支持这一点?根据我使用 EF 1:M 的经验,子表(地址)对于其父表(Person 或 Store)来说是唯一的。我将有一个 Person Table 和一个 PersonAddressTable 具有 1:M 关系。我也会有一个 Store 和 StoreAddress 表,它们有自己的 1:M 关系。不幸的是,现有的数据模型是这样写的。

据我了解,我通过在指向父级的子实体上添加导航属性来定义 1:M 关系。子实体还必须有一个指向父实体的 ID 字段 (FK),并且此 FK 属性必须在子实体上按要求标记。

所以在我的示例中,地址实体将具有

public virtual Person Person get;set;
public int PersonId get;set;    
public Virtual Store Store get;set;
public int StoreId get;set;

地址实体映射器将定义:

this.Property(i=>i.PersonId).IsRequired();
this.Property(i=>i.StoreId).IsRequired();

this.HasRequired(p=>p.Person)
.WithMany(c=>c.Addresses)
.HasForeignKey(c=>PersonId);

this.HasRequired(p=>p.Store)
.WithMany(c=>c.Addresses)
.HasForeignKey(c=>c.StoreId);

但根据其父级,子导航属性(Person 或 Store)将为空。当引用 Person 的地址时,Address.Store nav 属性将为 null,当引用商店的地址时,Address.person nav 属性将为 null。

如何正确定义这些关系?

谢谢。

【问题讨论】:

我可能错了,但我认为虚拟属性在您的地址类中是可选的。如果你想要延迟加载,你肯定需要它们。无论如何,如果您正在与一个人打交道,Addresses.Store 是否为 null 有什么关系,如果您正在与商店打交道,Addresses.Person 是否为 null 又有什么关系? 地址类中不应包含 PersonId 和 StoreId。只是虚拟属性很好。 如果地址类上没有PersonId和StoreId,如何在映射代码中指定关系? This.HasRequired(p=>p.Person) .WIthMany(c=>c.Addresses).HasForiegnKey(WHAT_GOES_HERE)? 我也有类似的问题。任何解决方案了吗? ***.com/questions/25042768/… 【参考方案1】:

我不确定如何使用 FluentAPI 进行操作,但这是使用 CodeFirst 的一种方法。

注意,Store 和 Person 引用的是 Address,而不是相反。

我将有以下三个课程:

public class AddressModel

    public int AddressId  get; set; 
    public string Line1  get; set; 
    public string Line2  get; set; 
    public string City  get; set; 
    public string State  get; set; 
    public string Zip  get; set; 


public class PersonModel

    public int PersonId  get; set; 
    public string FirstName  get; set; 
    public string LastName  get; set; 
    public List<AddressModel> Addresses  get; set; 


public class StoreModel

    public int StoreId  get; set; 
    public string StoreName  get; set; 
    public List<AddressModel> Addresses  get; set; 

【讨论】:

【参考方案2】:

首先,您是否在控制基础表或是否被现有表卡住并不清楚。但是,假设您确实可以控制该表并且只想将所有地址映射到单个表,您可以使用 TPH 来执行此操作。

请在下面找到如何设置的示例。

    public class AppContext : DbContext
    
        public DbSet<Person> People  get; set; 
        public DbSet<Store> Stores  get; set; 
        public DbSet<Address> Addresses  get; set; 
    

    public class Person
    
        public Person()
        
            Addresses = new HashSet<PersonAddress>();
        
        public int Id  get; set; 
        public string Name  get; set; 
        public virtual ICollection<PersonAddress> Addresses  get; set; 

    

    public class Store
    
        public Store()
        
           Addresses = new HashSet<StoreAddress>();
        
        public int Id  get; set; 
        public string StoreName  get; set; 

        public virtual ICollection<StoreAddress> Addresses  get; set; 

    

    public abstract class Address
    
        public int Id  get; set; 
        public string AddressInformation  get; set; 
    

    public class PersonAddress : Address
    
        public string PersonAddressInformation  get; set; 
    

    public class StoreAddress : Address
    
        public string StoreAddressInformation  get; set; 
    

由此生成的数据库表如下所示。

【讨论】:

以上是关于EF 代码第一个一对多(使用“通用”表)的主要内容,如果未能解决你的问题,请参考以下文章

代码第一个约定不在实体框架6.2中的多对多关系上创建连接表

2个表之间的关系 - 一对多和一对一(可空)EF代码优先

EF 使用lambda表达式 更新一对多数据时报错

当关联表是一个对所有一对多关系时,如何实现一对多映射?

EF基础知识小记五(一对多多对多处理)

Doctrine - 从反面查询一对多、单向的连接表关联