EF代码首选一对多(使用"通用"表)

时间:2014-03-22 01:27:46

标签: c# entity-framework ef-code-first

考虑以下示例:

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

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

我的理解是我通过在子实体上添加指向父级的nav属性来定义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)将为null。引用Person的地址时,Address.Store nav属性将为null,并且在引用商店的地址时,Address.person nav属性将为null。

如何正确定义这些关系?

感谢。

2 个答案:

答案 0 :(得分: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; }
}

答案 1 :(得分:0)

首先,它不能立即清楚您是否掌控了基础表,或者您是否遇到现有表。但是假设您确实控制了表并且只想将所有地址映射到单个表,则可以使用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; }
    }

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

TPH Table Diagram