問題
前の質問のようにテーブル分割を使用して、約 7 個のエンティティで大きなテーブル (200 以上のフィールド) を共有しようとしています。
EF6 では、プライマリ モデルから子モデルへのナビゲーション プロパティだけでなく、すべての子モデル間でのナビゲーション プロパティが必要です (これは最悪です)。
手動ソリューション
これは手動で行うことができます:
public class Franchise
{
[Key]
public int Id { get; set; }
public virtual FranchiseEntity Entity { get; set; }
public virtual FranchiseMiscellaneous Miscellaneous { get; set; }
}
[Table("Franchise")]
public class FranchiseEntity
{
[Key]
public int Id { get; set; }
public virtual FranchiseEntity Entity { get; set; } // Ignored, but relevant when inheritance involved, below...
public virtual FranchiseMiscellaneous Miscellaneous { get; set; }
}
[Table("Franchise")]
public class FranchiseMiscellaneous
{
[Key]
public int Id { get; set; }
public virtual FranchiseEntity Entity { get; set;
public virtual FranchiseMiscellaneous Miscellaneous { get; set; } // Ignored, but relevant when inheritance involved, below...
}
スムーズなマッピング:
public class FranchiseMapping : EntityTypeConfiguration<Franchise>
{
public FranchiseMapping()
{
HasRequired(x => x.Entity).WithRequiredPrincipal();
HasRequired(x => x.Miscellaneous).WithRequiredPrincipal();
}
}
public class FranchiseEntityMapping : EntityTypeConfiguration<FranchiseEntity>
{
public FranchiseEntityMapping()
{
Ignore(x => x.Entity);
HasRequired(x => x.Miscellaneous).WithRequiredPrincipal(x => x.Entity);
}
}
public class FranchiseMiscellaneousMapping : EntityTypeConfiguration<FranchiseMiscellaneous>
{
public FranchiseMiscellaneousMapping()
{
Ignore(x => x.Miscellaneous);
}
}
これは機能します。しかし、これは 7 つ以上のモデルではうまくスケールアップしません。
#1 を改善しようとする
継承 + DRY 原則を通じて改善したいと思います。
public abstract class SharedFranchiseIdBase
{
[Key]
public int Id { get; set; }
public virtual FranchiseEntity Entity { get; set; }
public virtual FranchiseMiscellaneous Miscellaneous { get; set; }
}
public class Franchise : SharedFranchiseIdBase { ... }
public class FranchiseEntity : SharedFranchiseIdBase { ... }
public class FranchiseMiscellaneous : SharedFranchiseIdBase { ... }
// Maybe generalize the mapping code too...
しかし、これは「シーケンスに複数の一致する要素が含まれています」という最初のリクエストで失敗します:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.InvalidOperationException: Sequence contains more than one matching element
Result StackTrace:
at System.Linq.Enumerable.Single[TSource](IEnumerable`1 source, Func`2 predicate)
at System.Data.Entity.ModelConfiguration.Configuration.Properties.Navigation.NavigationPropertyConfiguration.ConfigureDependentBehavior(AssociationType associationType, EdmModel model, EntityTypeConfiguration entityTypeConfiguration)
at System.Data.Entity.ModelConfiguration.Configuration.Properties.Navigation.NavigationPropertyConfiguration.Configure(NavigationProperty navigationProperty, EdmModel model, EntityTypeConfiguration entityTypeConfiguration)
at System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.ConfigureAssociations(EntityType entityType, EdmModel model)
at System.Data.Entity.ModelConfiguration.Configuration.Types.EntityTypeConfiguration.Configure(EntityType entityType, EdmModel model)
at System.Data.Entity.ModelConfiguration.Configuration.ModelConfiguration.ConfigureEntities(EdmModel model)
at System.Data.Entity.DbModelBuilder.Build(DbProviderManifest providerManifest, DbProviderInfo providerInfo)
at System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)
at System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext)
at System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input)
at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
at System.Data.Entity.Internal.Linq.InternalSet`1.get_InternalContext()
at System.Data.Entity.Infrastructure.DbQuery`1.System.Linq.IQueryable.get_Provider()
at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
... // my test query function
改善の試み #2
私はそれらをabstractと宣言できると思ったので、少なくともプログラマーは正しいメンバーを実装することを余儀なくされます(派生クラスごとに再宣言するのはまだ面倒です):
public abstract class SharedFranchiseIdBase
{
[Key]
public int Id { get; set; }
public abstract FranchiseEntity Entity { get; set; }
public abstract FranchiseMiscellaneous Miscellaneous { get; set; }
}
public class Franchise : SharedFranchiseIdBase
{
[Key]
public int Id { get; set; }
public override FranchiseEntity Entity { get; set; }
public override FranchiseMiscellaneous Miscellaneous { get; set; }
}
//etc for other classes
しかし、これは同じエラーが発生したときに失敗します。は??クラス定義は、「仮想」ではなく「オーバーライド」と宣言されていることを除いて、作業コピーと同一です。E/F が、PropertyInfo.ReflectedType に関係なく、PropertyInfos または何かにインデックスを付けているかのようです。
改善の試み #3
インターフェイスを使用してパターンを強制することもできますが、かなり奇妙に見え始めている各クラスでインターフェイスを宣言する必要があるため、これはあまり好ましくありません。
public class Franchise : SharedFranchiseIdBase, ISharedFranchiseId { ... }
public class FranchiseEntity : SharedFranchiseIdBase, ISharedFranchiseId { ... }
public class FranchiseMiscellaneous : SharedFranchiseIdBase, ISharedFranchiseId { ... }
は?
これは E/F のバグですか? 基本クラスのプロパティを派生クラスのプロパティと同じように扱うのに苦労していますか?
説明が長くなってしまい申し訳ありません、今朝の全調査のまとめです。