簡體   English   中英

實體框架查詢問題

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM