简体   繁体   English

实体框架查询问题

[英]Problems With Entity Framework Queries

I write a Class, it's has some query. 我写了一个类,它有一些查询。 attention, the whereitem is a little class, its Body member include a Expression<Fun<T,bool>> lambda expression is used to filter the query 注意,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;
}

and then, when i run it, I get a error, it said "LINQ to Entities query does not support the query builder method. For more information, please refer to the Entity Framework documentation." 然后,当我运行它时,出现错误,它说“ LINQ to Entities查询不支持查询生成器方法。有关更多信息,请参阅Entity Framework文档。”

so i change my code. 所以我改变我的代码。

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

so. 所以。 it's ok, but is ugly,right? 可以,但是很难看,对吗? the WHERE is after ORDERBY. WHERE在ORDERBY之后。 when i change their location, I get a error. 当我更改他们的位置时,我得到一个错误。 Type isn't match. 类型不匹配。 What other good way? 还有什么其他好的方法?

==================Additional============================== ==================其他===============================

In order to facilitate the reception call this method passing a string (eg "it.UserId desc") over the OrderItem sort statement, in fact WhereItem is Expression > the package, my question is not whether to implement the filter is entityframework statement, but can split chain operation, because if the first implementation of the Where in the query after he converted to IQueryObject not ObjectQuery type, so once cast, after the implementation of Orderby an error. 为了方便接收调用,此方法在OrderItem排序语句上传递字符串(例如“ it.UserId desc”),实际上WhereItem是Expression> package,我的问题不是是否要执行过滤器是entityframework语句,而是可以拆分链操作,因为如果先在查询中执行Where,之后将其转换为IQueryObject而不是ObjectQuery类型,那么一旦强制转换,执行Orderby就会出错。 Such as: 如:

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

DataService that I wrapped up the class. 我包装了该类的DataService。 The equivalent of a DAO. 相当于DAO。 But is realized EF. 但是实现了EF。 Some queries can be passed, but some are not. 可以传递一些查询,但不能传递。 The reasons are not clear. 原因尚不清楚。 But certainly because of the type conversion caused. 但是肯定是因为类型转换引起的。 I'm using. 我正在使用。 Net 3.5sp1 vs2010 default entity data model (. Edmx) Net 3.5sp1 vs2010默认实体数据模型(.edmx)

If I direct the implementation of query.OrderBy (xxx). 如果我直接执行query.OrderBy(xxx)。 Skip (xx). 跳过(xx)。 Where (xxx). 其中(xxx)。 Take (xx). 取(xx)。 ToList () to return results, but there are some problems, he is the first order filter obtained in the skip last xx months . ToList()返回结果,但是存在一些问题,他是在最近xx个月的跳过中获得的一阶过滤器。

I would like to query.Where (XX). 我想查询。(XX)。 OrderBy (xxx). OrderBy(xxx)。 Skip (xx). 跳过(xx)。 Take (xx). 取(xx)。 ToList ()... but can not be performed because the Where (Expression) to return but not ObjecteQuery IEnumerable (parameter type Expression of the time) or IQueryable (parameter of type Func time). ToList()...,但不能执行,因为要返回Where(表达式),但不返回ObjecteQuery IEnumerable(参数类型为time的表达式)或IQueryable(类型为Func time的参数)。 Where can only be placed on the back, while Skip to call after they have OrderBy, Where so awkward in the middle of ... 只能放在背面,而在有了OrderBy之后可以跳过呼叫,而在中间居中则很尴尬...

Here's what I believe is happening: 我相信这是正在发生的事情:

you can't apply the .Where(whereitem.Body) to the query because it contains a custom function expression that the Entity Framework does not know how to translate into SQL to execute on the database. 您不能将.Where(whereitem.Body)应用于查询,因为它包含一个自定义函数表达式,实体框架不知道该表达式如何转换为SQL以在数据库上执行。

when you put the .Where(whereitem.Body) after the.OrderBy(orderString).Skip(start) it works fine because calling .OrderBy(orderString).Skip(start) has caused the sql to execute and has returned an in memory IEnumerable that you can now execute your .Where(whereitem.Body) on that in memory collection. 当您将.Where(whereitem.Body)放在.OrderBy(orderString).Skip(start)之后时,它可以正常工作,因为调用.OrderBy(orderString).Skip(start)已导致sql执行并返回了内存IEnumerable,您现在可以在内存集合中的该对象上执行.Where(whereitem.Body)。 it doesn't need to translate that expression to sql anymore, but executes it as CLR. 它不再需要将该表达式转换为sql,而是将其作为CLR执行。 you could use a simple lambda expression in the Where that is translatable to SQL, or you can force the sql to evaluate earlier by doing query.AsEnumerable().Where(...) ofcourse this will load a lot more results from the db into memory before performing the filtering. 您可以在可以转换为SQL的Where中使用简单的lambda表达式,也可以通过执行query.AsEnumerable()。Where(...)强制sql进行更早的评估,这当然会从数据库中加载更多结果在执行过滤之前将其存入内存。

also, filtering after skip and take will give you different results than filtering first. 同样,跳过和带走之后的过滤将为您带来与第一次过滤不同的结果。

On second thought, what you really need is this: 再次考虑,您真正需要的是:

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


}

you need to pass the lambda expression as a simple predicate, i believe that should let it be translatable to SQL. 您需要将lambda表达式作为一个简单的谓词传递,我认为应该让它可转换为SQL。 (ofcourse given that the predicate consists of simple expressions that are themselves translatable by EF to sql.) (当然,谓词由简单的表达式组成,这些表达式本身可以被EF转换为sql。)

I have find the way. 我找到了办法。

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

we can use the extend method SortEngine 我们可以使用扩展方法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