EFコア:複数のゼロ/一対多の関係の間で外部キーのプロパティを共有する方法

c# entity-framework entity-framework-core inheritance

質問

だから私は少しEFコアに浸漬しており、継承と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;");
    }
}

基本的に、代理店、キャリア、プリンシパルはすべて党から継承しているので、党と同じ性質を持つべきです。代理店と運送業者にはさらに特有の特性があり、手数料との関係が0または1対多でなければなりません。さらに、プリンシパルには特定のプロパティがいくつかありますが、手数料との関係はありません。

結果データベースは次のとおりです。 結果のEFデータベース

パーティーテーブル自体の出力に問題はなく、識別子フィールドが何であるか理解していますが、作成した2つの外部キーの関係はわかりません。

  • Commissions_AgencyPartyIdの締約国
  • Commissions_CarrierPartyIdの締約国

私の質問は、なぜ私は締約国からバックエンドのCommissions_PartyIdに1つの外部キー関係を持つことができないのですか?私ができれば、どうやってEFにそのように伝えることができますか?

EDIT

ドミトリーの提案を使用し、[InverseProperty]属性を使用して、私は目的の出力ではない次のデータベース設計で終わった: InversePropertyからの結果データベース

それは実際に第3フィールド(PartyId1)を作った。だから私は関係についてのEF ドキュメントをもう一度見て、別々の注釈で遊び始めました。 [ForeignKey( "PartyId")]属性を使用すると、私が期待しているデザインが作成された後、

ForeignKey属性の結果データベース

しかし、これにも予期しない影響がありました。代理店と運送業者でデータベースを設定しようとすると、例外が発生します。

コードには次のようなものがあります。

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.Actency」と入力すると「EFTest.Carrierタイプのオブジェクトをキャストできません」という例外があります。

オリジナルのEFデザインを使用すると、プログラムが期待どおりに機能することを追加しますが、追加のフィールドと外部キーによってOCDが少し狂っています:)それ以上の考えは歓迎です!

受け入れられた回答

外部キーと同じプロパティーを使用するように両方のリレーションシップを構成する場合、依然として2つの関係があります。追加するときに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は合法ですか? はい、理由を学ぶ