EF Core:如何在幾個零/一對多關係之間共享外鍵屬性

c# entity-framework entity-framework-core inheritance

所以我稍微沉浸在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有幾個特定屬性,但與佣金無關。

生成的數據庫如下: 產生的EF數據庫

我對締約方表本身的輸出沒有任何問題,並了解鑑別器字段是什麼,但我不理解它創建的兩個外鍵關係:

  • Commissions_AgencyPartyId的各方
  • Commissions_CarrierPartyId的各方

我的問題是為什麼我不能只在後端與委員會_PartyId之間建立一個外鍵關係?如果可以,我怎麼能告訴EF以這種方式創建呢?

編輯

使用Dmitry的建議並使用[InverseProperty]屬性,我最終得到了以下數據庫設計,這不是所需的輸出: 來自InverseProperty的結果數據庫

它實際上是第三個字段(PartyId1)。所以我開始再次查看有關關係的EF 文檔,並開始使用不同的註釋。在生成我期望的設計之後,使用[ForeignKey(“PartyId”)]屬性給了我一些希望:

從ForeignKey屬性生成的數據庫

然而,這也有一些意想不到的效果。在嘗試使用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;
        }

添加代理商時的例外情況是“無法將類型為'EFTest.Agency'的對象強制轉換為'EFTest.Carrier'。”嘗試添加Carrier時的例外是“無法將'EFTest.Carrier'類型的對象強制轉換為'EFTest.Agency'。”

我將補充一點,當使用原始EF設計時,程序確實按預期工作,但是額外的字段和外鍵使我的強迫症有點瘋狂:)歡迎任何更多的想法!

一般承認的答案

如果將兩個關係配置為使用與外鍵相同的屬性,則仍有兩個關係。因此,添加時, CommissionPartyId等於1 EF將其解釋為被相關的AgencyPartyId等於1 CarrierPartyId等於1,顯然這是不可能的。

你需要做的是在CommissionParty之間建立一種關係,但這意味著Commissions導航財產也需要轉移到Party 。但是你仍然可以將它隱藏在Principal和其他派生類上,方法是保護它並且只在AgencyCarrier上公開它:

public class PartyContext : DbContext
{
    public PartyContext(DbContextOptions options)
        : base(options)
    {
    }

    public DbSet<Agency> Agencies { get; set; }
    public DbSet<Carrier> Carriers { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Party>().HasMany(typeof(Commission), "Commissions").WithOne();
    }
}

public class Party
{
    public int PartyId { get; set; }
    protected ICollection<Commission> Commissions { get; set; }
}

public class Agency : Party
{
    public new ICollection<Commission> Commissions
    {
        get { return base.Commissions; }
        set { base.Commissions = value; }
    }
}

public class Carrier : Party
{
    public new ICollection<Commission> Commissions
    {
        get { return base.Commissions; }
        set { base.Commissions = value; }
    }
}

public class Commission
{
    public int Id { get; set; }
}

熱門答案

嘗試這個:

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; }
}


Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因