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

c# EF DbContext - generate object dynamically from string

我想创建一个工厂 class 到 return DbContext 对象,其中 table 名称将作为字符串传递。数据库中有 100 多个 table,每个都有不同的 structure/schema。

想法是将 tableName 作为 string 在将 return 对象放入 EF 的方法中传递,我们可以 select/update 这些记录。我在某篇文章中找到了这段代码,但对如何使用它有些困惑:

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

如果有任何其他方法可以实现同样的事情,请告诉我。

一个简单的方法是使用 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>)。

获取通用 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。

另一种选择是使用动态,但您不能将动态与 C# 扩展方法一起使用(不强制转换为具体类型),因此您又回到了没有 Linq 支持的同一条船上。

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

老实说,如果你有 100 个 类,我会硬着头皮写硬编码类型,或者像 CodeSmith 一样使用代码生成器为你做。