我想创建一个工厂类来返回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
的地方?
如果有其他方法可以达到同样的目的,请告诉我。
答案 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。