私のドメイン モデルには、Company
抽象化された基本クラスと、Company のサブクラスによって表される 3 つの異なる Company タイプがあります。
public abstract class Company
{
public int Id { get; set; }
...
}
public class Supplier : Company
{
...
}
public class Dealer : Company
{
public DealerFundsAccount FundsAccount { get; set; }
...
}
public class Retailer : Company
{
public RetailerFundsAccount FundsAccount { get; set; }
...
}
同様に、Funds Account を定義する別の基本クラスと、特定のプロパティを実装する 2 つのサブタイプがあります。
public abstract class FundsAccount
{
public int Id { get; set; }
...
}
public class DealerFundsAccount : FundsAccount
{
public Dealer Dealer { get; set; }
...
}
public class RetailerFundsAccount : FundsAccount
{
public Retailer Retailer { get; set; }
...
}
これらの型に対する私のマッピング戦略は、階層ごとのテーブルであるため、私の DbContext クラスでは、基本クラスに対してのみ DbSet を定義します。これにより、ポリモーフィック クエリと非ポリモーフィック クエリの両方を実行できるようになります。
public DbSet<Company> Companies { get; set; }
public DbSet<FundsAccount> FundsAccounts { get; set; }
ここでトリッキーな部分が来ます。私の要件は次のように述べています。
- サプライヤーは資金口座を持ってはなりません
- ディーラーには DealerFundsAccount が必要です
- 小売業者には RetailerFundsAccount が必要です
次のように単純なはずです。
modelBuilder.Entity<Retailer>()
.HasRequired(r => r.FundsAccount)
.WithRequiredDependent(rfa => rfa.Retailer);
modelBuilder.Entity<Dealer>()
.HasRequired(d => d.FundsAccount)
.WithRequiredDependent(dfa => dfa.Retailer);
しかし、EF Migrations はデータベース スキーマを更新しようとして惨めに失敗します。TPH により、Dealers と Retailers は同じ Company データベース テーブルにマップされ、RetailerFundsAccounts と DealerFundsAccounts は FundsAccount db テーブルにマップされます。これはすべて望ましいことですが、サブタイプ間に 2 つの 1 対 1 の関係を定義したため、EFはFundsAccount Id フィールドに外部キーを 2 回定義します。
資金口座を持つ Company テーブルごとに 1 対多の関係を定義し、FK の一意の制約を使用して 1 対多の動作を防止することで、ソリューションをハックできることはわかっていますが、より良い解決策があります。