だから私は少し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対多でなければなりません。さらに、プリンシパルには特定のプロパティがいくつかありますが、手数料との関係はありません。
パーティーテーブル自体の出力に問題はなく、識別子フィールドが何であるか理解していますが、作成した2つの外部キーの関係はわかりません。
私の質問は、なぜ私は締約国からバックエンドのCommissions_PartyIdに1つの外部キー関係を持つことができないのですか?私ができれば、どうやってEFにそのように伝えることができますか?
EDIT
ドミトリーの提案を使用し、[InverseProperty]属性を使用して、私は目的の出力ではない次のデータベース設計で終わった:
それは実際に第3フィールド(PartyId1)を作った。だから私は関係についてのEF ドキュメントをもう一度見て、別々の注釈で遊び始めました。 [ForeignKey( "PartyId")]属性を使用すると、私が期待しているデザインが作成された後、
しかし、これにも予期しない影響がありました。代理店と運送業者でデータベースを設定しようとすると、例外が発生します。
コードには次のようなものがあります。
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つの関係があります。追加するときにCommission
とPartyId
1 EFに等しいに関連していると解釈Agency
とPartyId
1に等しいと Carrier
とPartyId
1に等しく、これは明らかに不可能であろう。
あなたがする必要があるのは、 Commission
とParty
間の関係を作り出すことですが、これはCommissions
ナビゲーションプロパティをParty
にも移す必要があることを意味します。しかし、 Principal
やその他の派生クラスでは、それを保護され、 Agency
とCarrier
だけに公開することで、それを隠すことができます。
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; }
}