Отражение с IQueryable - PullRequest
       21

Отражение с IQueryable

2 голосов
/ 24 мая 2011

Я играю и пытаюсь создать метод расширения для IQueryable, который сортирует его по произвольному свойству объекта.

public static class IQueryableExtender

{

public static IQueryable<TSource> Sort<TSource>(this IQueryable<TSource> query, string orderProperty, string sortDirection = "asc")      
{

    var elementType = query.ElementType;

    var propertyInfo = elementType.GetProperty(orderProperty);
    if (propertyInfo == null)
    {
         throw new ArgumentException(string.Format("{0} is not a property on {1}", orderProperty, elementType.Name));
    }


    switch (sortDirection.ToLower())
    {
       case "asc":
       case "ascending":
           return query.OrderBy(x => propertyInfo.GetValue(x, null));
           break;
       case "desc":
       case "descending":
           return query.OrderByDescending(x => propertyInfo.GetValue(x, null));
           break;
    }

    return query;
}
}

Я получаю эту ошибку при вызове метода.Я предполагаю, что это связано с тем, что IQueryable еще не выполнил и не получил никаких объектов.

LINQ to Entities не распознает метод System.Object GetValue(System.Object, System.Object[]), и этот метод нельзя преобразовать в выражение хранилища.

Я могу решить эту проблему, выполнив ToList на IQueryable, но затем извлекаюданные в методе расширения, и это не то, что я хочу.

Можно ли это решить?

1 Ответ

2 голосов
/ 24 мая 2011

LINQ to Entities пытается выполнить ваши запросы в базе данных, когда вы выполняете операцию LINQ на IQueryable <>.В вашем case "asc" вы выполняете query.OrderBy, который LINQ to Entities интерпретирует как «преобразовать это в SQL», и он терпит неудачу, так как вы используете вызовы отражения, которые он не знает, как преобразовать в SQL.

Вы можете сделать query.AsEnumerable (). OrderBy (...).Одним из следствий этого является то, что при запуске операции OrderBy остальная часть запроса будет выполняться для предоставления данных.

Вместо того, чтобы использовать эти приемы отражения, вы могли бы получить, просто используяМетоды OrderBy и OrderByDescending, предназначенные для получения делегата для извлечения значения сортировки.(items.OrderBy(item => item.Property)).Вам не хватает возможности указать восходящий или нисходящий в том же методе, но я бы просто сделал пару методов, таких как:

public static IOrderedQueryable<TSource> OrderByAscDesc<TSource, TKey>(
    this IQueryable<TSource> source,
    Expression<Func<TSource, TKey>> keySelector, bool isAsc
) {
    return (isAsc ? source.OrderBy(keySelector) : source.OrderByDescending(keySelector);
}

public static IOrderedQueryable<TSource> OrderByAscDesc<TSource, TKey>(
    this IQueryable<TSource> source,
    Func<TSource, TKey> keySelector, bool ascDesc
) {
    return (isDesc ? source.OrderBy(keySelector) : source.OrderByDescending(keySelector);
}
...