[英]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.