EF Code First - 通过反射为所有实体调用MapInheritedProperties()

时间:2015-06-17 09:34:52

标签: c# entity-framework reflection ef-code-first code-first

根据我的需要,我试图通过使用Reflection调用MapInheritedProperties()来为我的实体强制使用TPC(Table Per Concrete类)。

所以我想要的是在DbContext的OnModelCreating方法中为我的所有实体进行这样的调用

modelBuilder.Entity<MyEntity>().Map(o => o.MapInheritedProperties())

我尝试做的是这个但是我没有成功创建方法MapInheritedProperties()的委托因为我得到以下异常:无法绑定到目标方法,因为它的签名或安全透明度与此不兼容委托类型。

foreach (var feEntityType in this.GetEntityTypes(onlyConcreteClasses: true))
{
    // modelBuilder.Entity<Person>()
    var entityMethodInvoked = modelBuilder.GetType().GetMethod("Entity").MakeGenericMethod(feEntityType).Invoke(modelBuilder, null);

    // o.MapInheritedProperties()
    ParameterExpression parameterExpression = ParameterExpression.Parameter(typeof(EntityMappingConfiguration<>).MakeGenericType(feEntityType), "o");
    MethodInfo methodInfo = typeof(EntityMappingConfiguration<>).MakeGenericType(feEntityType).GetMethod("MapInheritedProperties", new Type[] { });
    Expression mapInheritedPropertiesMethodExpression = Expression.Call(parameterExpression, methodInfo);

    // Method Map<T>(...)
    var mapMethod = typeof(EntityTypeConfiguration<>)
        .MakeGenericType(feEntityType)
        .GetMethods()
        .Single(o => o.Name == "Map" && o.IsGenericMethod);

    // Func<EntityMappingConfiguration<MonEntite>>
    var mapMethodParameterType = typeof(Func<>).MakeGenericType(typeof(EntityMappingConfiguration<>).MakeGenericType(feEntityType));
    var mapAction = methodInfo.CreateDelegate(mapMethodParameterType); // <== DOESN'T WORK ==> Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.

    var mapMethodInvoked = mapMethod.MakeGenericMethod(feEntityType).Invoke(entityMethodInvoked, new[] { /* PARAMETER */ });
}

以下是我获取具体实体的方法

protected IEnumerable<Type> GetEntityTypes(bool onlyConcreteClasses = false)
{
    var entityTypes = typeof(EntitiesLocation).Assembly.GetTypes().Where(o => o.GetInterfaces().Contains(typeof(IEntity)));

    foreach (var item in entitiesTypes)
    {
        if (onlyConcreteClasses && item.IsAbstract)
            continue;

        yield return item;
    }
}

关于如何创建委托的任何想法?或者为我的所有实体调用方法MapInheritedProperties()而不必手动制作它的另一种方法?

1 个答案:

答案 0 :(得分:0)

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{
    //do whatever to get your entity Types
    var entityTypes = typeof(EntitiesLocation).Assembly.GetTypes()
        .Where(x => x.IsClass && !x.IsAbstract && x.GetInterfaces()
        .Any(i => i == typeof(IEntity)));

    foreach (var entityType in entityTypes)
    {
        GetType().GetMethod(nameof(MapInheritedProperties))
            .MakeGenericMethod(entityType)
            .Invoke(this, new object[] { modelBuilder });
    }
}

public void MapInheritedProperties<TEntity>(DbModelBuilder modelBuilder) where TEntity : class
{
    modelBuilder.Entity<TEntity>().Map(m => m.MapInheritedProperties());
}