c#EF DbContext - 从字符串动态生成对象

时间:2015-03-08 17:40:07

标签: c# entity-framework objectcontext

我想创建一个工厂类来返回DbContext对象,其中表名将作为字符串传递。数据库中有100多个表,每个表都有不同的结构/模式。

我们的想法是将tableName作为string传递给将在EF中返回对象的方法,我们可以选择/更新这些记录。我在一些文章中发现了这个代码,但是如何使用它有一些困惑:

public ObjectContext Context(EntityObject entity)
{
        var relationshipManager = ((IEntityWithRelationships)entity).RelationshipManager;
        var wrappedOwnerProperty = relationshipManager.GetType().GetProperty("WrappedOwner", BindingFlags.Instance | BindingFlags.NonPublic);
        var wrappedOwner = wrappedOwnerProperty.GetValue(relationshipManager);
        var contextProperty = wrappedOwner.GetType().GetProperty("Context");
        return (ObjectContext)contextProperty.GetValue(wrappedOwner);
}

我不确定这是否是我需要的。我还应该传递EntityObject entity以及我应该通过tableName的地方?

如果有其他方法可以达到同样的目的,请告诉我。

1 个答案:

答案 0 :(得分:6)

一种简单的方法是使用DbContext.Set()方法,并根据字符串获取类型。

using (var db = new MyDbContext)
{
    string tableName = "ApplicationUser";
    var type = Assembly.GetExecutingAssembly()
       .GetTypes()
       .FirstOrDefault(t => t.Name == tableName);

    if(type != null)
    DbSet catContext = context.Set(type);    
}

然而,这有一个缺点,即这是一个非通用的DbSet(即它是DbSet而不是DbSet<T>)。

获取Generic DbSet(允许linq功能)的方法是执行以下操作:

using (var db = new IdentityDbContext())
{
    string tableName = "ApplicationUser";
    var type = Assembly.GetExecutingAssembly()
       .GetTypes().FirstOrDefault(t => t.Name == tableName);

    var method = db.GetType().GetMethods()
       .First(x => x.IsGenericMethod && x.Name == "Set");

    MethodInfo generic = method.MakeGenericMethod(type);
    var set = generic.Invoke(db, null);
}

当然set会在这里成为一个对象,你必须以某种方式抛出它,这仍然是问题的一部分。

当它归结为它时,如果你不打算使用静态编译的类型,你将不得不继续处理反射,特别是当你有通用类型来处理时(即DbSet<T>等等。你必须在某些时候将它们转换为静态类型来调用方法,或者继续执行MethodInfo.Invoke&#39; s。

另一种选择是使用动态,但你不能使用c#扩展方法的动态(没有强制转换为具体类型),所以你回到了没有Linq支持的同一条船上。

通过反射使用Linq是一个巨大的痛苦。

老实说,如果你有100个课程,我只需咬紧牙关并编写硬编码类型,或者使用代码生成器为你做类似CodeSmith。