より良い見出しが見つからないことをお詫び申し上げます。MEFモジュールを介してEF4CTP5モデルを拡張しようとしています。アイデアは、いくつかの基本的なエンティティを指定することです。これらの基本エンティティは、ソリューションモデルアセンブリのContextクラスの隣にあります。
たとえば、Variableというエンティティがあります。変数は非常に一般的なエンティティであり、アプリケーションの一部のモジュールで特別な変数エンティティを指定して、より詳細なプロパティを提供する必要がありますが、それらは同じテーブル(TPH-階層ごとのテーブル)に格納する必要があります。
そのために、インターフェイスIModelContextExtensionを指定しました
public interface IModelContextExtension
{
void OnModelCreating(IModelBuilderFacade modelBuilder);
}
カスタム変数を使用する各モジュールは、このインターフェイスを実装するクラスをエクスポートする必要があります。モデルのOnModelCreatingメソッドで、登録されている各モジュールをループし、そのモジュールのOnModelCreatingメソッドを呼び出します。次に、提供されたIModelBuilderFacadeで「RegisterVariableType」などを呼び出して、Variable-Derived-Type(MySpecialVariable2など)をアナウンスできます。
**興味深い部分:** Variable-Derived-Typeが別の(MEF-Loaded)アセンブリにある場合を除いて、RegisterVariableTypeメソッドは非常にうまく機能しているようです。別のモジュールから変数を登録すると、完全なマッピングが破損しているように見えます。なぜなら、リポジトリに変数を追加しようとすると、追加中に「シーケンスに要素が含まれていません」と表示されてクラッシュするからです。ロードされたモジュールからタイプを削除すると、期待どおりに機能します。
誰かが興味を持っているなら、私はIRepositoryのものを投稿しますが、それは問題ではないと確信しています。
ここに、私のコンテキスト(DbContextから派生)クラスのOnModelCreatingメソッドがあります。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var modelBuilderFacade = new ModelBuilderFacade(modelBuilder);
modelBuilder.Entity<Variable>().HasKey(x => new { x.Id });
////////////////////////////////////
// register derived VariableTypes
modelBuilderFacade.RegisterVariableType(typeof(MySpecialCyclicVariable));
modelBuilderFacade.RegisterVariableType(typeof(MyVerySpecialVariable));
//modelBuilder.Entity<Variable>().HasKey(x => new { x.Id }); modelBuilder.Entity<Variable>()
// .Map<MySpecialVariabe>(m => m.Requires(DiscriminatorColumn).HasValue(typeof(MySpecialVariabe).Name))
// .Map<MyVerySpecialVariable>(m => m.Requires(DiscriminatorColumn).HasValue(typeof(MyVerySpecialVariable).Name))
// .ToTable(VariableTable);
if (ModelExtensions != null)
{
foreach (var modelContextExtension in ModelExtensions)
{
modelContextExtension.OnModelCreating(modelBuilderFacade);
}
}
Map<Variable>(modelBuilder, modelBuilderFacade.VariableTypes, VariableTable);
////////////////////////////////////
}
RegisterVariableType関数は、modelBuilderFacadeに格納されているIEnumerableに(Variable派生)型を追加します。
タイプを追加した後、自分のMap関数を呼び出してTPHマッピングを実行します。
[Export(typeof(IModelContextExtension))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class Context : IModelContextExtension
{
public void OnModelCreating(IModelBuilderFacade modelBuilder)
{
modelBuilder.RegisterVariableType(typeof(MyVerySpecialVariable2));
}
}
ここでMap関数:
private static void Map<T>(ModelBuilder modelBuilder, IEnumerable<Type> types, string table) where T : class
{
var entityTypeConfigurarion = modelBuilder.Entity<T>();
foreach (var variableType in types)
{
if (!typeof(T).IsAssignableFrom(variableType))
{
throw new InvalidOperationException(string.Format("Cannot map type '{0}' to type {1}", variableType, typeof(T)));
}
// #1: Get the generic Map method of the EntityTypeConfiguration<T>
MethodInfo genericMapMethod = GetGenericEntityTypeConfigurationMapMethod<T>(variableType);
// #2: Get generic type of RequiredMappingActionFactory
var requiredMappingFactoryType = typeof(RequiredMappingActionFactory<>).MakeGenericType(variableType);
// #3 get the action from generic mapping factory
var action = requiredMappingFactoryType.GetProperty("RequiredMappingAction").GetValue(null, null);
entityTypeConfigurarion =
genericMapMethod.Invoke(
entityTypeConfigurarion,
BindingFlags.Public | BindingFlags.Instance,
null,
new [] { /* and the */ action /* goes here */ },
null) as EntityTypeConfiguration<T>;
}
if (entityTypeConfigurarion == null)
{
throw new CompositionException("Something went terrible wrong!");
}
entityTypeConfigurarion.ToTable(table);
}
private static MethodInfo GetGenericEntityTypeConfigurationMapMethod<T>(Type variableType) where T : class
{
var mapMethod =
typeof(EntityTypeConfiguration<T>).GetMethods().Where(
mi => mi.Name == "Map" && mi.IsGenericMethodDefinition).FirstOrDefault();
return mapMethod.MakeGenericMethod(variableType);
}
そしてここでRequiredMappingActionFactory
internal static class RequiredMappingActionFactory<T> where T : class
{
public static string DiscriminatorColumn = "Discriminator";
public static Action<EntityMappingConfiguration<T>> RequiredMappingAction { get { return RequiredAction; } }
public static void RequiredAction(EntityMappingConfiguration<T> configuration)
{
configuration.Requires(DiscriminatorColumn).HasValue(typeof(T).Name);
}
}
うまくいけば、誰かが私を助けてくれるといいのですが、よろしくお願いします、
ケリオ、クリス