我写了一个类,它有一些查询。注意,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;
}
如此。没关系,但是很难看,对吗? OREREBY之后的WHERE。当我改变他们的位置时,我得到一个错误。类型不匹配。还有什么好方法?
==================附加============================ ==
为了便于接收调用,该方法在OrderItem排序语句上传递字符串(例如“it.UserId desc”),实际上WhereItem是Expression&gt;这个包,我的问题不是是否实现过滤器是entityframework语句,而是可以拆分链操作,因为如果第一次执行其中的查询后他转换为IQueryObject而不是ObjectQuery类型,那么一旦执行,执行后订单错误。 如:
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(Expression)返回而不是ObjecteQuery IEnumerable(参数类型表达式的时间)或IQueryable(参数类型为Func时间)。哪里只能放在后面,而在他们有OrderBy之后跳过来打电话,在中间尴尬......
答案 0 :(得分:1)
以下是我认为正在发生的事情:
您不能将.Where(whereitem.Body)应用于查询,因为它包含一个自定义函数表达式,实体框架不知道如何将其转换为SQL以在数据库上执行。
当你把.Where(whereitem.Body)放在.OrderBy(orderString).Skip(start)之后它工作正常,因为调用.OrderBy(orderString).Skip(start)导致sql执行并返回在内存中IEnumerable,您现在可以在内存集合中执行.Where(whereitem.Body)。它不再需要将该表达式转换为sql,而是将其作为CLR执行。你可以在Where可以转换为SQL的地方使用一个简单的lambda表达式,或者你可以通过执行query.AsEnumerable()来强制sql先评估。其中(...)ofcourse这将从db加载更多的结果在执行过滤之前进入内存。
另外,跳过和拍摄后过滤会得到与先过滤不同的结果。
第二个想法,你真正需要的是:
Find<T>(..., Func<TEntity,bool> predicate, ...)
{
...
query.Where(predicate)...
}
你需要将lambda表达式作为简单谓词传递,我相信应该让它可以转换为SQL。 (当然,假设谓词由简单的表达式组成,这些表达式本身可以通过EF转换为sql。)
答案 1 :(得分:0)
我找到了方法。
http://www.codeproject.com/KB/linq/IEnumerableSortByName.aspx?msg=3005452#xx3005452xx
我们可以使用extend方法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);
}