2010-07-22 2 views
0

Я пишу класс, у него есть запрос. Внимание, whereitem немного класса, его член тел включает в себя выражение а Expression<Fun<T,bool>> лямбды используются для фильтрации запросаПроблемы с запросами Framework Entity

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

so. это нормально, но уродливо, не так ли? WHERE после ORDERBY. когда я меняю свое местоположение, я получаю сообщение об ошибке. Тип не соответствует. Какой еще хороший способ?

Дополнительная информация ============================================================================================================================================================= ===

Чтобы облегчить прием, вызовите этот метод, передавая строку (например, «it.UserId desc») над оператором сортировки OrderItem, на самом деле WhereItem является выражением> пакет, мой вопрос заключается не в том, следует ли реализовать фильтр является выражением сущности, но может разделить операцию цепочки, потому что если первая реализация 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 месяцев.

Я хотел бы запросить.Where (XX). OrderBy (xxx). Пропустить (xx). Возьмите (xx). ToList() ... но не может быть выполнено, потому что возвращаемое значение Where (Expression), но не ObjecteQuery IEnumerable (тип параметра Expression of the time) или IQueryable (параметр времени типа Func). Где могут быть размещены только на спине, в то время как Скип звонить после того как они имеют OrderBy, где так неловко в середине ...

+0

@user: просьба представить немного подробно о том, что проблема на самом деле происходит. Есть ли исключение? Тогда, пожалуйста, опубликуйте его. Не все из нас могут читать мысли. –

ответ

1

Вот что я считаю, что происходит:

вы не можете применить. Где (whereitem.Body) к запросу, потому что он содержит специальное выражение функции, которое Entity Framework не знает, как перевести на SQL для выполнения в базе данных.

Когда вы положили .Where (whereitem.Body) после .OrderBy (orderString) .Skip (start) работает отлично, потому что вызов .OrderBy (orderString) .Skip (start) вызвал выполнение sql и имеет возвратил в памяти IEnumerable, что теперь вы можете выполнить свой .Where (whereitem.Body), который находится в коллекции памяти. ему больше не нужно переводить это выражение в sql, но выполняет его как CLR. вы можете использовать простое выражение лямбда в том, что можно перевести на SQL, или вы можете заставить sql оценивать ранее, выполняя запрос. AsEnumerable(). Где (...), конечно, это будет загружать намного больше результатов из db в память перед выполнением фильтрации.

также, фильтрация после пропустить и принять даст вам различные результаты, чем фильтрация в первую очередь.

На второй мысли, что вам действительно нужно, это:

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


} 

вам нужно передать лямбда-выражение как простой предикат, я считаю, что должно позволить ей быть переводимым в SQL. (при условии, что предикат состоит из простых выражений, которые сами по себе транслируются EF в sql.)

+0

Я обновил вопрос – Dreampuf

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); 
} 
Смежные вопросы