EF Core:如何在几个零/一对多关系之间共享外键属性

时间:2016-12-15 16:14:08

标签: c# entity-framework inheritance entity-framework-core

所以我稍微深入EF Core并尝试继承和TPH模式(我之前没有经验)。 EF创建的结果数据库不是我所期望的,我想知道是否可以使用fluent-api获得我想要的结果,或者我是否完全忽略了这一点。

首先,这是我的POCO课程:

public class Commission
{
    public int Id { get; set; }
    public string Description { get; set; }
    public double Rate { get; set; }
}

public class Party
{
    public int PartyId { get; set; }
    public string Name { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
}

public class Agency : Party
{
    public string AgencyCode { get; set; }
    public ICollection<Commission> Commissions { get; set; }
}

public class Carrier : Party
{
    public string CarrierCode { get; set; }
    public ICollection<Commission> Commissions { get; set; }
}

public class Principal : Party
{
    public string Website { get; set; }
    public string DistrictCode { get; set; }
}

我的上下文类以防万一:

public class PartyContext : DbContext
{
    public DbSet<Agency> Agencies { get; set; }
    public DbSet<Carrier> Carriers { get; set; }
    public DbSet<Party> Parties { get; set; }
    public DbSet<Commission> Commissions { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(@"Server=LAPTOP-PC\SQLEXPRESS;Database=MyDatabase;Trusted_Connection=True;");
    }
}

基本上,代理商,承运人和委托人都是从党继承的,所以他们应该拥有与党相同的所有财产。代理商和承运人具有其他特定属性,并且与委员会之间应具有零或一对多的关系。此外,Principal有几个特定属性,但与佣金无关。

生成的数据库如下: Resulting EF Database

我对Parties表本身的输出没有任何问题,并且理解鉴别器字段是什么,但是我不理解它创建的两个外键关系:

  • Commissions_AgencyPartyId
  • 的各方
  • Commissions_CarrierPartyId
  • 的各方

我的问题是为什么我不能在后端与委员会_PartyId之间建立一个外键关系?如果可以的话,我如何告诉EF以这种方式创建它?

修改

使用Dmitry的建议并使用[InverseProperty]属性,我最终得到了以下数据库设计,这不是所需的输出: Resulting Database from InverseProperty

它实际上是第三个字段(PartyId1)。所以我开始再次查看EF documentation on relationships并开始使用不同的注释。使用[ForeignKey(&#34; PartyId&#34;)]属性给我带来了一些希望,因为它产生了我期待的设计:

Resulting Database from ForeignKey attribute

然而,这也有一些意想不到的效果。在尝试使用Agency和Carrier填充数据库之后,我收到了一个例外。

这是填充代码:

PartyContext _context = new PartyContext();
        // Add an Agency
        var agencyCommission1 = new Commission
        {
            Description = "Contract",
            Rate = 0.075
        };

        var agencyCcommission2 = new Commission
        {
            Description = "Hauling",
            Rate = 0.10
        };

        var agencyCommissionList = new List<Commission>
        {
            agencyCommission1, agencyCcommission2
        };

        var agency = new Agency
        {
            Name = "Agency International",
            Address1 = "12345 Main Street",
            Address2 = "Suite 100",
            City = "Chicago",
            State = "IL",
            Zip = "31202",
            AgencyCode = "AI",
            Commissions = agencyCommissionList
        };

        // Add Carrier
        var carrierCommission1 = new Commission
        {
            Description = "Coal",
            Rate = 0.15
        };

        var carrierCommission2 = new Commission
        {
            Description = "Mining",
            Rate = 0.115
        };

        var carrierCommissionList = new List<Commission>
        {
            carrierCommission1, carrierCommission2
        };

        var carrier = new Carrier
        {
            Name = "Carrier International",
            Address1 = "54321 Main Street",
            Address2 = "Suite 300",
            City = "Cleveland",
            State = "OH",
            Zip = "44115",
            CarrierCode = "CI",
            Commissions = carrierCommissionList
        };

        _context.Agencies.Add(agency);
        _context.Carriers.Add(carrier);

        try
        {
            _context.SaveChanges();
        }
        catch(Exception ex)
        {
            return;
        }

添加代理商时的例外情况是&#34;无法投放类型&#39; EFTest.Agency&#39;输入&#39; EFTest.Carrier&#39;。&#34;尝试添加运营商时的例外情况是&#34;无法投射类型&#39; EFTest.Carrier&#39;输入&#39; EFTest.Agency&#39;。&#34;

我将补充说,在使用原始EF设计时,程序确实按预期工作,但是额外的字段和外键使我的强迫症有点疯狂:)欢迎任何更多的想法!

2 个答案:

答案 0 :(得分:4)

如果将两个关系配置为使用与外键相同的属性,则仍然有两个关系。因此,当添加Commission PartyId等于1 EF时,将其解释为与Agency相关,PartyId等于1 a { {1}} Carrier等于1,显然这是不可能的。

您需要做的是在PartyIdCommission之间建立关系,但这意味着需要将Party导航属性移至Commissions同样。但是,您仍然可以将其隐藏在Party和其他派生类上,方法是将其隐藏起来并仅在PrincipalAgency上公开:

Carrier

答案 1 :(得分:0)

试试这个:

public class Commission
{
    public int Id { get; set; }
    public string Description { get; set; }
    public double Rate { get; set; }

    public Party Party { get; set; } // <-- "parent" party link here
}

public class Agency : Party
{
    public string AgencyCode { get; set; }

    [InverseProperty("Party")] // <-- link this collection with Party.Party
    public ICollection<Commission> Commissions { get; set; }
}

public class Carrier : Party
{
    public string CarrierCode { get; set; }

    [InverseProperty("Party")] // <-- link this collection with Party.Party
    public ICollection<Commission> Commissions { get; set; }
}