实体框架多个父表

时间:2012-09-21 10:50:12

标签: asp.net-mvc-3 sql-server-2008 entity-framework

我有一个现有的数据库,我试图通过Entity Framework 4.3访问。大多数表格和关系都不是问题,但是这组表格给我带来了一些我似乎无法找到答案的问题。

以下是(简明)实体:

客户

public class Customer
{
    public int CustomerID { get; set; }
    public string Name { get; set; }

    private int addressSourceTypeID = 2;
    [NotMapped]
    public int AddressSourceTypeID { 
        get { return addressSourceTypeID; } 
        set { addressSourceTypeID = value; } }

    public virtual ICollection<User> Users { get; set; }
    public virtual ICollection<Contract> Contracts { get; set; }
    public virtual ICollection<Address> Addresses { get; set; }
}

合同

public class Contract
{
    public int ContractID { get; set; }
    public string Name { get; set; }

    private int addressSourceTypeID = 4;
    [NotMapped]
    public int AddressSourceTypeID { 
        get { return addressSourceTypeID; } 
        set { addressSourceTypeID = value; } }

    public virtual int CustomerID { get; set; }
    public virtual Customer Customer { get; set; }

    //public virtual ICollection<Address> Addresses { get; set; }
}

地址

public class Address
{
    [Key]
    public int AddressID { get; set; }
    public int AddressSourceTypeID { get; set; }

    [ForeignKey("Customer")]
    public int SourceKey { get; set; }

    public virtual Customer Customer { get; set; }
    //public virtual Contract Contract { get; set; }
    public virtual ICollection<Contact> Contacts { get; set; }
}

我上面提到的是两个实体CustomerContract,它们都可以包含子Address个实体。目前,Address实体已设置为Customer实体的子级,但由于Contract没有指向Address的链接,因此效果很好。

我已尝试将Contract添加到Address实体,就像我对Customer实体所做的那样,您可以从注释掉的代码段中看到。不幸的是,这不起作用,但由于在Customer ForeignKey注释中引用了Address,我并不感到惊讶。我甚至尝试创建Address实体的特定版本(即CustomerAddress),但是当多个实体尝试绑定到同一个表时,我收到错误。

我也尝试在EF ModelBuilder中使用DBContext但是我的知识非常有限,我不知道在这种情况下如何做。

总的来说,我需要的是以下内容:

  • 拥有子地址集合的客户实体。
  • 合同实体拥有子地址集合。

这些“父”表与地址表之间的链接使用以下内容:

  • 客户:CustomerID =&gt;地址:SourceKey AND Customer:AddressSourceTypeID(总是2)=&gt;地址:AddressSourceTypeID。
  • 合同:ContractID =&gt;地址:SourceKey和合同:AddressSourceTypeID(总是4)=&gt;地址:AddressSourceTypeID。

如果有人能帮助我,或指出我的方向正确,那就太好了。

非常感谢。

1 个答案:

答案 0 :(得分:2)

您可以让EF使用每个层次结构继承表强制执行SourceKey属性 - 然后您的映射将中断,或者您可以在业务逻辑中强制执行SourceKey并且只有EF管理主Address类。

如果您必须维护当前的数据库架构,我认为让您的业务逻辑强制执行您的SourceKey作为分歧者是您唯一的选择:

public class Address
{
    public int AddressID { get; set; }
    public int AddressSourceTypeID { get; set; }
    public int SourceKey { get; set; }
    public virtual Contract Contract { get; set; }
    public virtual Customer Customer { get; set; }
}
public class Contract
{
    public Contract()
    {
        this.Addresses = new List<Address>();
    }

    public int ContractID { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Address> Addresses { get; set; }
}
public class Customer
{
    public Customer()
    {
        this.Addresses = new List<Address>();
    }

    public int CustomerID { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Address> Addresses { get; set; }
}

这是你流利的映射:

        modelBuilder.Entity<Address>().HasOptional(t => t.Contract)
            .WithMany(t => t.Addresses)
            .HasForeignKey(d => d.SourceKey);
        modelBuilder.Entity<Address>().HasOptional(t => t.Customer)
            .WithMany(t => t.Addresses)
            .HasForeignKey(d => d.SourceKey);

或者 - 如果您创建了CustomerAddressContractAddress,则可以使用TPH继承强制执行SourceKey - 但目前无法映射导航属性:

public abstract class Address
{
    [Key]
    public int AddressID { get; set; }
    public int AddressSourceTypeID { get; set; }

    public int SourceKey { get; set; }
}

public class CustomerAddress : Address
{
    public virtual Customer Customer { get; set; }
}

public class ContractAddress : Address
{
    public virtual Contract Contract { get; set; }
}

这是你的映射:

        modelBuilder.Entity<Address>()
            .Map<ContractAddress>(m => m.Requires("AddressSourceTypeID").HasValue(2))
            .Map<CustomerAddress>(m => m.Requires("AddressSourceTypeID").HasValue(4));

这将强制AddressSourceTypeID作为您的鉴别者 - 遗憾的是,此处的细分是将您的导航属性映射回ContractAddress和客户地址。请参阅具有相同基本问题的this related post。也许这会让你开始朝着正确的方向前进。