Проблемы с запросами Entity Framework - PullRequest
0 голосов
/ 22 июля 2010

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

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

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

================== Дополнительная ============================ ==

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

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

Ответы [ 2 ]

1 голос
/ 22 июля 2010

Вот что я думаю:

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

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

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

Если подумать, то, что вам действительно нужно, это:

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


}

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

0 голосов
/ 23 июля 2010

Я нашел способ.

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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...