【问题标题】:Entity Framework Dynamic DbSet for all entities所有实体的实体框架动态 DbSet
【发布时间】:2013-04-10 10:06:30
【问题描述】:

我有一个用实体框架映射的数据库,

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

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”

有什么想法吗!?

注意,dbContext的方法Set()不行;类型应该明确给出...

【问题讨论】:

  • 您可能需要更正实际代码中“custommer”->“customer”的拼写。

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


【解决方案1】:

为避免switch,您可以通过其程序集限定名称查找类型,然后从中获取DbSet。以这种方式检索到的 DbSet 不是泛型,因此您可以执行的操作更加有限。

您可以通过使用已知的实体类型(例如Product)获取程序集限定名称,获取其程序集限定名称,然后将“Product”替换为所需名称以获得类型。

此示例是从 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;
  }
}

【讨论】:

    【解决方案2】:

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

    另请注意,在您原来的 getGenericList() 中,您总是返回一个空列表,而不是您通过 EF 获得的列表。您还使用了 2 个不同的 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 语句,通常这可能表明您需要重新考虑您的方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-02-10
      • 1970-01-01
      • 2011-07-15
      • 1970-01-01
      • 1970-01-01
      • 2016-12-21
      • 1970-01-01
      • 2013-04-05
      相关资源
      最近更新 更多