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