2个外键,1个导航属性可以通过两个

时间:2016-12-06 17:14:23

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

鉴于以下粗略的代码优先架构,目标看起来非常简单。 Invoice可以来自Company,也可以Invoicespublic class Company { public int Id { get; set; } public virtual ICollection<Invoice> Invoices { get; set; } } public class Invoice { public int Id { get; set; } public int FromCompanyId { get; set; } public int ToCompanyId { get; set; } public virtual Company FromCompany { get; set; } public virtual Company ToCompany { get; set; } } 集合应该包含所有发票,无论它是什么。

Company_Id

您会在迁移中注意到,出于显而易见的原因生成了第三个Invoices以支持Invoices导航属性,因为仅 以支持1 Nav Prop - &GT; 1 FK安排。

我的问题是,是否可以让IC<Inv> InvoicesFrom属性包含两者,或者我是否应该单独映射它们(即IC<Inv> InvoicesToInverseProperty)并创建客户端 - 手动收集。

我试过了:

  1. FromCompanyToCompany上使用[ForeignKey(nameof(FromCompanyId)), InverseProperty(nameof(Company.Invoices))] public virtual Company FromCompany { get; set; } [ForeignKey(nameof(ToCompanyId)), InverseProperty(nameof(Company.Invoices))] public virtual Company ToCompany { get; set; } 会混淆EF,因为它无法确定关系的主要结束。

        modelBuilder.Entity<Company>()
            .HasMany(m => m.Invoices)
            .WithRequired(m => m.ToCompany)
            .WillCascadeOnDelete(false);
        modelBuilder.Entity<Company>()
            .HasMany(m => m.Invoices)
            .WithRequired(m => m.FromCompany)
            .WillCascadeOnDelete(false);
    
  2. 使用流畅的API来映射它们,但它只考虑从代码角度来看的第二个。

    {{1}}
  3. 如果不可能的话,当然没有重大问题,我可以发誓我以前做过。

1 个答案:

答案 0 :(得分:1)

对于后代,这里是一个完整版本的变通方法,用于维护包含两个集合在一起的公司的IEnumerable<Invoices>

public class MyContext : DbContext
{
    public MyContext() : base("DefaultConnection") { }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Company>().HasMany(c => c.InvoicesFrom).WithRequired(i => i.FromCompany).WillCascadeOnDelete(false);
        modelBuilder.Entity<Company>().HasMany(c => c.InvoicesTo).WithRequired(i => i.ToCompany).WillCascadeOnDelete(false);
    }

    public DbSet<Company> Companies { get; set; }
    public DbSet<Invoice> Invoices { get; set; }
}

public class Company
{
    public int Id { get; set; }
    public virtual ICollection<Invoice> InvoicesFrom { get; set; }
    public virtual ICollection<Invoice> InvoicesTo { get; set; }

    [NotMapped]
    public IEnumerable<Invoice> Invoices
    {
        get {
            return InvoicesFrom.Union(InvoicesTo);
        }
    }
}

public class Invoice
{
    public int Id { get; set; }
    public int FromCompanyId { get; set; }
    public int ToCompanyId { get; set; }
    public virtual Company FromCompany { get; set; }
    public virtual Company ToCompany { get; set; }
}