2010-07-22 83 views
0

我寫了一個類,它有一些查詢。注意,該whereitem有點類,它的主體構件包括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到實體查詢不支持查詢構建器方法。有關更多信息,請參閱實體框架文檔。「

所以我改變我的代碼。

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

所以。沒關係,但很醜陋,對吧? ORDERBY之後的WHERE。當我改變他們的位置時,我得到一個錯誤。類型不匹配。還有什麼其他好方法?其他=========================== ===

爲了方便接收調用這個方法在OrderItem排序語句上傳遞一個字符串(例如「it.UserId desc」),實際上WhereItem是Expression>包,我的問題不是是否要實現該過濾器是entityframework語句,但是可以拆分鏈式操作,因爲如果先執行Where中的查詢之後,他將其轉換爲IQueryObject而不是ObjectQuery類型,那麼一旦執行了Cast,執行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()返回結果,但存在一些問題,他是在skip的最後xx個月中獲得的一階過濾器。

我想query.Where(XX)。 OrderBy(xxx)。跳過(xx)。拿(xx)。 ToList()...但不能執行,因爲Where(表達式)返回但不是ObjecteQuery IEnumerable(參數類型表達式的時間)或IQueryable(參數類型爲Func時間)。如果只能放在後面,而跳過調用後,他們有排序依據,凡在中間這麼彆扭......

+0

@user:請提供什麼問題實際上出現一個小細節。是否有例外?然後請張貼它。並非我們所有人都能讀懂頭腦。 – 2010-07-22 01:59:14

回答

1

這就是我認爲正在發生的事情:

您不能應用。 where(whereitem.Body)給查詢,因爲它包含一個自定義函數表達式,該實體框架不知道如何轉換成SQL來執行數據庫。 (orderString).Skip(start)它工作正常,因爲調用.OrderBy(orderString).Skip(start)已經導致sql執行並且已經擁有了.OrderBy(orderString).Skip返回一個內存IEnumerable,你現在可以在內存集合中執行你的.Where(whereitem.Body)。它不需要將該表達式轉換爲SQL,而是將其作爲CLR執行。你可以在Where可以轉換爲SQL的地方使用一個簡單的lambda表達式,或者你可以通過執行query.AsEnumerable()來強制執行sql以前的計算。where(...)ofcourse這會從db中加載更多的結果在執行過濾之前進入內存。

另外,skip和take之後的過濾會給你比先過濾的結果不同。

關於第二個想法,你真正需要的是這樣的:

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


} 

你需要傳遞lambda表達式作爲一個簡單的斷言,我認爲,應該讓它可翻譯爲SQL。 (當然,謂詞由簡單表達式組成,它們本身可以由EF轉換爲sql)。

+0

我更新了問題 – Dreampuf 2010-07-22 08:54:15

0

我找到了方法。

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