繁体   English   中英

实体框架查询问题

[英]Problems With Entity Framework Queries

我写了一个类,它有一些查询。 注意,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查询不支持查询生成器方法。有关更多信息,请参阅Entity Framework文档。”

所以我改变我的代码。

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之后。 当我更改他们的位置时,我得到一个错误。 类型不匹配。 还有什么其他好的方法?

==================其他===============================

为了方便接收调用,此方法在OrderItem排序语句上传递字符串(例如“ it.UserId desc”),实际上WhereItem是Expression> package,我的问题不是是否要执行过滤器是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()返回结果,但是存在一些问题,他是在最近xx个月的跳过中获得的一阶过滤器。

我想查询。(XX)。 OrderBy(xxx)。 跳过(xx)。 取(xx)。 ToList()...,但不能执行,因为要返回Where(表达式),但不返回ObjecteQuery IEnumerable(参数类型为time的表达式)或IQueryable(类型为Func time的参数)。 只能放在背面,而在有了OrderBy之后可以跳过呼叫,而在中间居中则很尴尬...

我相信这是正在发生的事情:

您不能将.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进行更早的评估,这当然会从数据库中加载更多结果在执行过滤之前将其存入内存。

同样,跳过和带走之后的过滤将为您带来与第一次过滤不同的结果。

再次考虑,您真正需要的是:

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


}

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

我找到了办法。

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);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM