【问题标题】:Entity Framework multiple parent tables实体框架多个父表
【发布时间】:2012-09-21 23:32:24
【问题描述】:

我有一个试图通过 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 实体的子实体,这工作正常,因为没有从AddressContract 的链接。

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

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

总的来说,我需要的是:

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

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

  • 客户:CustomerID => 地址:SourceKey AND 客户:AddressSourceTypeID(始终为 2)=> 地址:AddressSourceTypeID。
  • 合同:ContractID => 地址:SourceKey AND 合同:AddressSourceTypeID(始终为 4)=> 地址:AddressSourceTypeID。

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

非常感谢。

【问题讨论】:

  • 数据库中Address表中的SourceKey列是both一对多关系的外键???这在技术上是允许的,您可以在 SourceKey 上为 CustomerContract 导航属性使用两个 [ForeignKey] 注释。但这意味着每当Address 通过SourceKey FK 引用Customer“1234”时,也必须有Contract“1234”,反之亦然——这很难想象,因为CustomerContract 以一对多的关系关联,您的密钥看起来像自动生成的身份。

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


【解决方案1】:

您可以让 EF 使用 Table per Hierarchy Inheritance 强制执行您的 SourceKey 属性 - 然后您的映射将中断,或者您可以在您的业务逻辑中强制执行 SourceKey 并且只让 EF 管理主要的 @987654324 @类。

如果您必须维护当前的数据库架构,我认为让您的业务逻辑强制执行您的 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 - 但目前无法映射 Nav 属性:

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。也许这至少会让你朝着正确的方向前进。

【讨论】:

  • 几乎 100% 工作,我唯一遇到的问题是我需要使 SourceKey 可以为空。非常感谢。
  • 不幸的是,使用它仍然会在 efcore3.1 中产生约束,可能是因为 optional 不可用。一旦我尝试添加在第一个关联实体中找不到的源键,约束就会生效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-17
  • 2010-11-28
相关资源
最近更新 更多