C# EF4 CTP5:通过MEF模块-TPH-OnModelCreating扩展模型
很抱歉没有找到更好的标题。我试图通过MEF模块扩展EF4 CTP5模型:其思想是指定一些基本实体。这些基本实体位于解决方案模型程序集中上下文类的旁边 例如,将有一个名为Variable的实体。变量是一个非常通用的实体,我希望应用程序的一些模块指定提供更详细属性的特殊变量实体,但它们应该存储在同一个表中(TPH-每个层次的表) 为此,我指定了一个接口IModelContextensionC# EF4 CTP5:通过MEF模块-TPH-OnModelCreating扩展模型,c#,.net,entity-framework-4,mef,entity-framework-ctp5,C#,.net,Entity Framework 4,Mef,Entity Framework Ctp5,很抱歉没有找到更好的标题。我试图通过MEF模块扩展EF4 CTP5模型:其思想是指定一些基本实体。这些基本实体位于解决方案模型程序集中上下文类的旁边 例如,将有一个名为Variable的实体。变量是一个非常通用的实体,我希望应用程序的一些模块指定提供更详细属性的特殊变量实体,但它们应该存储在同一个表中(TPH-每个层次的表) 为此,我指定了一个接口IModelContextension public interface IModelContextExtension { void OnMo
public interface IModelContextExtension
{
void OnModelCreating(IModelBuilderFacade modelBuilder);
}
要使用自定义变量的每个模块都必须导出一个实现此接口的类。在模型的OnModelCreating方法中,我循环每个注册的模块,并调用该模块的OnModelCreating方法。然后,它可以在提供的IModelBuilderFacade上调用例如“RegisterVariableType”,以宣布变量派生类型(例如MySpecialVariable2)
**有趣的是:**
RegisterVariableType方法似乎工作得很好,除非变量派生类型位于另一个(MEF加载的)程序集中。如果我从另一个模块注册一个变量,那么完整的映射似乎会被破坏。因为,当我现在尝试向其存储库添加变量时,它在添加过程中崩溃,并说:“序列不包含任何元素”。如果我从加载的模块中删除该类型,它将按预期工作
如果有人感兴趣,我会发布我的推荐资料,但我相信这不是问题所在
这里是my context(派生自DbContext)类的OnModelCreating方法:
以下是地图功能:
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);
}
私有静态无效映射(ModelBuilder ModelBuilder、IEnumerable类型、字符串表),其中T:class
{
var entityTypeConfigurarion=modelBuilder.Entity();
foreach(类型中的变量variableType)
{
如果(!typeof(T).IsAssignableFrom(variableType))
{
抛出新的InvalidOperationException(string.Format(“无法将类型{0}映射到类型{1}”)、variableType、typeof(T));
}
//#1:获取EntityTypeConfiguration的通用映射方法
MethodInfo genericMapMethod=GetGenericeEntityTypeConfigurationMapMethod(variableType);
//#2:获取RequiredMappingActionFactory的通用类型
var requiredMappingFactoryType=typeof(RequiredMappingActionFactory)。MakeGenericType(variableType);
//#3从通用映射工厂获取操作
var action=requiredMappingFactoryType.GetProperty(“RequiredMappingAction”).GetValue(null,null);
实体类型配置=
genericMapMethod.Invoke(
entityTypeConfigurarion,
BindingFlags.Public | BindingFlags.Instance,
无效的
新的[]{/*和*/action/*放在这里*/},
null)作为EntityTypeConfiguration;
}
if(entityTypeConfigurarion==null)
{
抛出新的CompositionException(“出现了严重错误!”);
}
entityTypeConfigurarion.ToTable(表格);
}
私有静态方法信息GetGenericeEntityTypeConfigurationMapMethod(类型variableType),其中T:class
{
var映射法=
typeof(EntityTypeConfiguration).GetMethods()。其中(
mi=>mi.Name==“Map”&&mi.IsGenericMethodDefinition).FirstOrDefault();
返回mapMethod.MakeGenericMethod(variableType);
}
这里是所需的MappingActionFactory
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);
}
}
内部静态类RequiredMappingActionFactory其中T:class
{
公共静态字符串鉴别器column=“鉴别器”;
公共静态操作RequiredMappingAction{get{return RequiredAction;}}
公共静态void RequiredAction(EntityMappingConfiguration配置)
{
configuration.Requires(DiscriminatorColumn).HasValue(typeof(T).Name);
}
}
希望有人能帮我,
致以最良好的祝愿
切里奥,
克里斯实体框架4.1 RC发布! 我试过了,我成功了:-) 请参见此处的自定义映射函数,该函数允许动态添加TPH映射
protected void MapEntity(
DbModelBuilder modelBuilder, Type entityType, string toTable, string discriminatorColumn = "Discriminator")
{
var method =
GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Where(
mi => mi.Name.StartsWith("MapEntity") && mi.IsGenericMethodDefinition).FirstOrDefault();
var genericMethod = method.MakeGenericMethod(entityType);
genericMethod.Invoke(this, new object[] { modelBuilder, toTable, discriminatorColumn });
}
protected void MapEntity<T>(
DbModelBuilder modelBuilder, string toTable, string discriminatorColumn = "Discriminator")
where T : class, IEntity
{
var config = modelBuilder.Entity<T>().Map(
entity =>
{
entity.MapInheritedProperties();
entity.Requires(discriminatorColumn).HasValue(typeof(T).FullName).IsOptional();
});
config.ToTable(toTable);
}
受保护的void映射实体(
DbModelBuilder modelBuilder,类型entityType,字符串toTable,字符串鉴别器Column=“鉴别器”)
{
var方法=
GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)。其中(
mi=>mi.Name.StartsWith(“MapEntity”)&&mi.IsGenericMethodDefinition.FirstOrDefault();
var genericMethod=method.MakeGenericMethod(entityType);
Invoke(这个,新对象[]{modelBuilder,toTable,discriminatorColumn});
}
受保护的空映射实体(
DbModelBuilder modelBuilder,字符串toTable,字符串鉴别器column=“鉴别器”)
式中T:类,属性
{
var config=modelBuilder.Entity().Map(
实体=>
{
entity.MapInheritedProperties();
entity.Requires(discriminatorColumn).HasValue(typeof(T).FullName).iso可选();
});
配置ToTable(ToTable);
}
以及使用示例:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
MapEntity<Variable>(modelBuilder, toTable: "Variables");
MapEntity<Variable2>(modelBuilder, toTable: "Variables");
foreach (var entityType in ModelExtensions.SelectMany(modelExtension => modelExtension.IntroduceModelEntities()))
{
MapEntity(modelBuilder, entityType, toTable: "Variables");
}
}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
MapEntity(modelBuilder,toTable:“变量”);
MapEntity(modelBuilder,toTable:“变量”);
foreach(ModelExtensions.SelectMany中的var entityType(modelExtension=>modelExtension.IntroducteModelentities())
{
MapEntity(modelBuilder、entityType、toTable:“变量”);
}
}
干杯,
Chris如果有人感兴趣,我将通过电子邮件发送解决方案(是一个测试项目)。我对上述代码进行了更多测试,发现它确实是实体类的位置(程序集)。创建SimpleEntity后,我将其2个派生项放入模型程序集中(MySimpleEntity和MySimpleEntity2),它们被正确映射和加载,但位于另一个程序集中的第3个类(MySimpleEntity3)将使
protected void MapEntity(
DbModelBuilder modelBuilder, Type entityType, string toTable, string discriminatorColumn = "Discriminator")
{
var method =
GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Where(
mi => mi.Name.StartsWith("MapEntity") && mi.IsGenericMethodDefinition).FirstOrDefault();
var genericMethod = method.MakeGenericMethod(entityType);
genericMethod.Invoke(this, new object[] { modelBuilder, toTable, discriminatorColumn });
}
protected void MapEntity<T>(
DbModelBuilder modelBuilder, string toTable, string discriminatorColumn = "Discriminator")
where T : class, IEntity
{
var config = modelBuilder.Entity<T>().Map(
entity =>
{
entity.MapInheritedProperties();
entity.Requires(discriminatorColumn).HasValue(typeof(T).FullName).IsOptional();
});
config.ToTable(toTable);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
MapEntity<Variable>(modelBuilder, toTable: "Variables");
MapEntity<Variable2>(modelBuilder, toTable: "Variables");
foreach (var entityType in ModelExtensions.SelectMany(modelExtension => modelExtension.IntroduceModelEntities()))
{
MapEntity(modelBuilder, entityType, toTable: "Variables");
}
}