【问题标题】:Problems With Entity Framework Queries实体框架查询的问题
【发布时间】:2011-03-19 07:50:50
【问题描述】:

我写了一个类,它有一些查询。注意,whereitem 是一个小类,它的 Body 成员包含一个Expression<Fun<T,bool>> lambda 表达式,用于过滤查询

public override List<T> Find<T>(int start, int len = 10, IWhereItem<T> whereitem = null, IOrderItem<T> orders = null, bool isDetach = true)
{
  var context = getInstence();
  var edminfo = EdmMgr[typeof (T)];//EdmMgr Include some dataservice infomation
  ObjectQuery<T> query = context.CreateQuery<T>("[" + edminfo.TableName + "]");
  if (whereitem != null && whereitem.Body != null)
    query = query.Where(whereitem.Body).AsObjectQuery();
  string orderString = orders == null ? "it." + edminfo.KeyName + " asc" : orders.OrderString;
  List<T> result = start == -1
             ? query.OrderBy(orderString).ToList()
             : query.OrderBy(orderString).Skip(start).Take(len).ToList();
  //......and else
  return result;
}

然后,当我运行它时,我得到一个错误,它说“LINQ to Entities 查询不支持查询构建器方法。有关更多信息,请参阅实体框架文档。”

所以我改变了我的代码。

public override List<T> Find<T>(int start, int len = 10, IWhereItem<T> whereitem = null, IOrderItem<T> orders = null, bool isDetach = true)
{
  var context = getInstence();
  var edminfo = EdmMgr[typeof (T)];
  ObjectQuery<T> query = context.CreateQuery<T>("[" + edminfo.TableName + "]");
  query = MemerVisitor.IncludeMembers.Aggregate(query, (current, str) => current.Include(str));
  string orderString = orders == null ? "it." + edminfo.KeyName + " asc" : orders.OrderString;
  List<T> result = query.OrderBy(orderString).Skip(start).Where(whereitem.Body).Take(len).ToList();
  return result;
}

所以。没关系,但很丑,对吧? WHERE 在 ORDERBY 之后。当我改变他们的位置时,我得到一个错误。类型不匹配。还有什么好办法?

===================补充============================ ==

为了方便接收调用这个方法传递一个字符串(如“it.UserId desc”)过OrderItem排序语句,其实WhereItem就是Expression>包,我的问题不是是否实现过滤器是entityframework语句,但是可以拆分链式操作,因为如果在查询中先执行Where后他转换为IQueryObject不是ObjectQuery类型,所以一旦强制转换,执行Orderby后会报错。 如:

      using (DataService<User> db = new DataService<User>())
            {
                user = db.Find(x => x.Moreinfo.CopSchool.CopSchoolId == 13&& x.Role.Title.Equals("xxxx")).FirstOrDefault();
            }

我完成了课程的DataService。相当于一个 DAO。而是实现了EF。 有些查询可以通过,但有些则不能。原因尚不清楚。但肯定是因为类型转换造成的。我正在使用。 Net 3.5sp1 vs2010 默认实体数据模型(.edmx)

如果我直接执行query.OrderBy(xxx)。跳过 (xx)。哪里(xxx)。取(xx)。 ToList()返回结果,但是有一些问题,他是skip last xx个月得到的一阶过滤器。

我想查询。哪里(XX)。 OrderBy (xxx)。跳过 (xx)。取(xx)。 ToList()...但是不能执行,因为Where(Expression)返回的却不是ObjecteQuery IEnumerable(参数类型Expression的时间)或IQueryable(参数类型Func时间)。 where 只能放在后面,而 Skip 之后就可以调用了 OrderBy,Where 中间那么别扭……

【问题讨论】:

  • @user:请提供一些关于实际发生的问题的细节。有例外吗?那么请发帖。并非所有人都能读心。

标签: c# entity-framework


【解决方案1】:

这是我认为正在发生的事情:

您不能将 .Where(whereitem.Body) 应用于查询,因为它包含实体框架不知道如何转换为 SQL 以在数据库上执行的自定义函数表达式。

当您将 .Where(whereitem.Body) 放在 .OrderBy(orderString).Skip(start) 之后时,它可以正常工作,因为调用 .OrderBy(orderString).Skip(start) 会导致 sql 执行并返回一个内存 IEnumerable,您现在可以在内存集合上执行您的 .Where(whereitem.Body) 。它不再需要将该表达式转换为 sql,而是将其作为 CLR 执行。您可以在可转换为 SQL 的 Where 中使用一个简单的 lambda 表达式,或者您可以通过执行 query.AsEnumerable().Where(...) 来强制 sql 更早地进行评估,当然这将从数据库中加载更多结果在执行过滤之前进入内存。

另外,在 skip 和 take 之后过滤会得到与先过滤不同的结果。

转念一想,你真正需要的是:

Find<T>(..., Func<TEntity,bool> predicate, ...)
{
...
query.Where(predicate)...


}

您需要将 lambda 表达式作为一个简单的谓词传递,我相信应该让它可以转换为 SQL。 (当然前提是谓词由简单的表达式组成,这些表达式本身可以被 EF 翻译成 sql。)

【讨论】:

    【解决方案2】:

    我已经找到方法了。

    http://www.codeproject.com/KB/linq/IEnumerableSortByName.aspx?msg=3005452#xx3005452xx

    我们可以使用扩展方法SortEngine

    private static IOrderedEnumerable<T> SortEngine<T>(this IEnumerable<T> source, string columnName, bool isAscending, bool started)
    {
        var item = Expression.Parameter(typeof(T), "item");
        var propertyValue = Expression.PropertyOrField(item, columnName);
        var propertyLambda = Expression.Lambda(propertyValue, item);
        // item => item.{columnName}
    
        var sourceExpression = Expression.Parameter(typeof(IEnumerable<T>), "source");
    
        string methodName;
        Expression inputExpression;
        if (started)
        {
            methodName = isAscending ? "ThenBy" : "ThenByDescending";
            inputExpression = Expression.Convert(sourceExpression, typeof(IOrderedEnumerable<T>));
            // ThenBy requires input to be IOrderedEnumerable<T>
        }
        else
        {
            methodName = isAscending ? "OrderBy" : "OrderByDescending";
            inputExpression = sourceExpression;
        }
    
        var sortTypeParameters = new Type[] { typeof(T), propertyValue.Type };
        var sortExpression = Expression.Call(typeof(Enumerable), methodName, sortTypeParameters, inputExpression, propertyLambda);
        var sortLambda = Expression.Lambda<Func<IEnumerable<T>, IOrderedEnumerable<T>>>(sortExpression, sourceExpression);
        // source => Enumerable.OrderBy<T, TKey>(source, item => item.{columnName})
    
        return sortLambda.Compile()(source);
    }
    
    public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> source, string columnName)
    {
        return SortEngine(source, columnName, true, false);
    }
    
    public static IOrderedEnumerable<T> OrderByDescending<T>(this IEnumerable<T> source, string columnName)
    {
        return SortEngine(source, columnName, false, false);
    }
    
    public static IOrderedEnumerable<T> ThenBy<T>(this IOrderedEnumerable<T> source, string columnName)
    {
        return SortEngine(source, columnName, true, true);
    }
    
    public static IOrderedEnumerable<T> ThenByDescending<T>(this IOrderedEnumerable<T> source, string columnName)
    {
        return SortEngine(source, columnName, false, true);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多