实体框架所有实体的动态DbSet

时间:2013-04-17 15:00:57

标签: linq-to-entities entity-framework-5 dynamic-data auto-generate

我有一个用Entity Framework映射的数据库,

我需要实现一个通用方法,根据我传递的参数获取项目列表:

getGenericList("product"); // returns the list of products
getGenericList("customer"); // returns the list of customers

我需要动态获取dbSet。我的方法实现如下:

public static List<object> getGenericList(string entityType)
    {
        List<object> myDynamicList = new List<object>();
        using (cduContext db = new cduContext())
        {
            DbSet dbSet = db.getDBSet(entityType);
            var myDynamicList = dbSet.Select(p => p).ToList();
        }
        return new List<object>();
    }

我的dbSets首先由EF代码自动生成:

public DbSet<Product> Products { get; set; }
public DbSet<Custommer> Custommers { get; set; }

我的getDBSet(entityType)方法在上下文中实现,如下所示:

public DbSet<T> getDBSet<T>(string entityName) where T : class
    {
        switch (entityName)
        {

            case "product":
                return Products;

            case "custommer":
                return Custommers;

然后我收到了这个错误:

  

无法将类型'System.Data.Entity.DbSet'隐式转换为'System.Data.Entity.DbSet'

请问任何想法!?

N.B。 ,Set()的方法dbContext不正常;该类型应明确给出......

2 个答案:

答案 0 :(得分:2)

最好远离字符串作为类型并将它们映射到实际类型;这是代码味道。相反,请使用类型本身。无论哪种方式,让我们重构使用getGenericList()方法的代码来使用泛型。如果您无法摆脱字符串,请在调用getGenericList()的代码中进行映射,而不是在该方法内进行映射,因为我们遵循您提出的模式。

另请注意,在您的原始getGenericList()中,您总是会返回一个空列表,而不是您通过EF获得的列表。您还使用了两个不同的myDynamicList变量;外部的一个被using语句范围内的那个掩盖,这就是为什么你没有得到编译器错误。一旦using超出范围,内部myDynamicList也会超出范围。我在这里解决了这个问题。

public static List<T> getGenericList<T>()
{
    List<T> myDynamicList;

    using (cduContext db = new cduContext())
    {
        // consider using exception handling here as GetDbSet might get an invalid type
        DbSet dbSet = db.GetDbSet<T>();
        myDynamicList = dbSet.Select(p => p).ToList();
    }

    if (myDynamicList != null && myDynamicList.Count() > 0)
    {
        return myDynamicList;
    }
    return new List<T>();
}

// in your context class
public DbSet<T> GetDbSet<T>() where T : class
{
    return this.Set<T>();
}

// this is the code that calls getGenericList(); put this inside a function somewhere. 
// entityName holds a string value, set previously
switch(entityName.ToLower()) // making entityName case insensitive
{
    case "product":
        return getGenericList<Product>();

    case "customer":
        return getGenericList<Customer>();
}

希望您不会有太多要映射的实体类型,或者您最终会得到一个巨大的switch语句。同样,如果你使用switch语句,一般来说这可能表明你需要重新思考你的方法。

答案 1 :(得分:0)

要避免switch,您可以按其程序集限定名称查找Type,然后从中获取DbSet。以这种方式检索的DbSet不是通用的&lt;&gt;,因此您可以执行的操作更加有限。

您可以使用已知的实体类型(例如Product)获取程序集限定名称,获取其程序集限定名称,然后替换&#34; Product&#34;使用所需的名称来获取类型。

此示例是从Breeze应用程序简化而来的,其中可以通过客户端的名称请求某些查找实体。

public async Task<List<object>> GetGenericList(string entityType)
{
  using (var context = new MyContext())
  {
    var aqtemp = typeof(Product).AssemblyQualifiedName; // template for qualified name

    var aqname = aqtemp.Replace("Product", entityType); // qualified name for entityType

    var type = Type.GetType(aqname, true, true);      // Type for entityType

    var list = await context.Set(type).ToListAsync(); // query the entities
    return list;
  }
}