EF如何在运行时从类型中获取DbSet名称?

4
目的: 我需要获取实体的dbset名称,例如typeof(UserAccount) = "UserAccounts"。但是在运行时,我需要循环的通用类型,并且不知道示例“UserAccount”,只知道typeof中的“name”。
我已创建了一个DbContext和一些实体。我已经谷歌搜索了一段时间,但由于类型转换,似乎无法为我工作?
请参见本描述底部的方法GetDbSetName。
我对这个EF的东西还很新-所以请帮助我解决我的问题。
public class MyEntities : DbContext
{
    public DbSet<UserAccount> UserAccounts { get; set;}
    public DbSet<UserRole> UserRoles { get; set; }
    public DbSet<UserAccountRole> UserAccountRoles { get; set; }
}

定义了一个类型列表来控制输出:

public static List<Type> ModelListSorted()
{
    List<Type> modelListSorted = new List<Type>();
    modelListSorted.Add(typeof(UserRole));
    modelListSorted.Add(typeof(UserAccountRole));
    modelListSorted.Add(typeof(UserAccount));
    return modelListSorted;
}

问题如下,使用 Type 时出现问题 - 如果我使用 "UserAccount",它可以正常工作并返回 "UserAccounts"。 但是在运行时,由于我处于一系列类型的循环中,我没有 "UserAccount"。 我只有 Type 列表提供了 e。
public static loopList()
{
    List<Type> modelListSorted = ModelListSorted();
    foreach (Type currentType in modelListSorted)
    {
         string s = DataHelper.GetDbSetName(currentType, db);
    } 
}

这里有一个方法让我挑战;-) 意思是编译错误。 说我缺少一个程序集? 我知道这很伪代码,但能否顺利完成?

public static string GetDbSetName(Type parmType, MyEntities db)
{
    string dbsetname = (db as IObjectContextAdapter).ObjectContext.CreateObjectSet<parmType>().EntitySet.Name;
    return dbsetname;
}
1个回答

3

这里的挑战在于涉及到两个反射步骤,一个是调用通用的CreateObjectSet方法,另一个是从结果中获取EntitySet。以下是一种实现方式:

首先,需要定义该方法:

string GetObjectSetName(ObjectContext oc, MethodInfo createObjectSetMethodInfo,
                        Type objectSetType, Type entityType)
{
    var objectSet = createObjectSetMethodInfo.MakeGenericMethod(entityType)
                                             .Invoke(oc, null);
    var pi = objectSetType.MakeGenericType(entityType).GetProperty("EntitySet");
    var entitySet = pi.GetValue(objectSet) as EntitySet;
    return entitySet.Name;
}

如您所见,我首先通过调用代表泛型方法CreateObjectSet<T>()MethodInfo来获取ObjectSet。然后我找到了泛型类型ObectSet<T>EntitySet属性的PropertyInfo。最后,我获得了该属性的值和所获得的EntitySet的名称。
为此,我首先获取了一个没有参数的CreateObjectSet<>()MethodInfo,以及ObjectSet<>类型。
var createObjectSetMethodInfo = 
    typeof(ObjectContext).GetMethods()
                         .Single(i => i.Name == "CreateObjectSet" 
                                   && !i.GetParameters().Any());

var objectSetType = Assembly.GetAssembly(typeof(ObjectContext))
                            .GetTypes()
                            .Single(t => t.Name == "ObjectSet`1");

GetObjectSetName中,它们的通用参数由具体实体类型指定,这是通过这些“MakeGeneric…”方法完成的。
var oc = (dbContextInstance as IObjectContextAdapter).ObjectContext;
var entityType = typeof(UserRole);
var name = GetObjectSetName(oc, createObjectSetMethodInfo, objectSetType, entityType);

在 EF 6 中,这应该是使用的 using
using System.Data.Entity.Core.Metadata.Edm
using System.Data.Entity.Core.Objects
using System.Data.Entity.Infrastructure
using System.Linq
using System.Reflection

嗨@GertArnold。感谢您的回复-思路简单而明了! 我在这一行代码中遇到了错误:var objectSet = createObjectSetMethodInfo.MakeGenericMethod(entityType).Invoke(oc, null); 异常信息:{"对象与目标类型不匹配。"} - pladekusken
还有这一行 var entitySet = pi.GetValue(objectSet) as EntitySet; 异常信息: {"对象不匹配目标类型。"} 你能帮忙解决这个问题吗? - pladekusken
我之前在我的引用中有Framework 6.1.1。 现在我已经将其删除并重新安装。 我现在可以编译您的代码而不需要更改。 我有以下使用: System.Linq; System.Reflection; System.Data.Entity.Core.Objects; System.Data.Metadata.Edm; using System.Data.Entity.Infrastructure; - pladekusken
但是这行代码 var entitySet = pi.GetValue(objectSet) as EntitySet; 返回了 null。 在调试时,我可以看到用于 GetValue 方法的 objectSet 中的值? - pladekusken
是的!它完美地运作了。非常感谢您的经验和耐心 :-) - pladekusken
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接