Когда ObjectQuery действительно является IOrderedQueryable? - PullRequest
3 голосов
/ 27 января 2012

Применительно к платформе сущностей методы расширения Select() и OrderBy() оба возвращают ObjectQuery, который определяется как:

public class ObjectQuery<T> : ObjectQuery, IOrderedQueryable<T>,
    IQueryable<T>, <... more interfaces>

Тип возврата Select() равен IQueryable<T>, а тип OrderBy равен IOrderedQueryable<T>. Таким образом, вы можете сказать, что оба возвращают один и тот же тип, но в другой оболочке. К счастью, потому что теперь мы можем применить ThenBy после вызова OrderBy.

Теперь моя проблема.

Допустим, у меня есть это:

var query = context.Plots.Where(p => p.TrialId == 21);

Это дает мне IQueryable<Plot>, то есть ObjectQuery<Plot>. Но это также IOrderedQueryable:

var b = query is IOrderedQueryable<Plot>; // True!

Но все же:

var query2 = query.ThenBy(p => p.Number); // Does not compile.
// 'IQueryable<Plot>' does not contain a definition for 'ThenBy'
// and no extension method 'ThenBy' ....

Когда я делаю:

var query2 = ((IOrderedQueryable<Plot>)query).ThenBy(p => p.Number);

Компилируется, но выдает исключение времени выполнения:

Выражение типа 'IQueryable`1[Plot]' нельзя использовать для параметра типа 'IOrderedQueryable`1[Plot] 'метода' IOrderedQueryable`1[Plot] ThenBy[Plot,Nullable`1](IOrderedQueryable`1[Plot], Expressions.Expression`1[System.Func`2[Plot,System.Nullable`1[System.Int32]]]) '

Приведение выполняется (я проверил), но параметр ThenBy по-прежнему рассматривается как IQueryable (что меня немного озадачивает).

Теперь предположим, что какой-то метод возвращает мне ObjectQuery<Plot> как IQueryable<Plot> (например, Select()). Что делать, если я хочу знать, безопасно ли вызывать ThenBy для возвращенного объекта. Как я могу понять это, если ObjectQuery является "реальным" или "фальшивым" IOrderedQueryable без ловли исключений?

Ответы [ 2 ]

2 голосов
/ 27 января 2012

Деревья выражений - действительно хорошее развлечение! (или, возможно, я немного ненормальный) и, вероятно, станет полезным для многих разработчиков в будущем, если Project Roslyn - это что-то! =)

В вашем случае, простое наследование от MSDN ExpressionVisitor и переопределение метода VisitMethodCall в наследующем классе с чем-то для сравнения m.MethodInfo с SortBy (т.е. если вы не слишком суетливы просто проверьте имя, если вы хотите быть суетливым, используйте отражение, чтобы получить фактическое SortBy MethodInfo для сравнения.

Дайте мне знать, если вам нужны примеры, но, если честно, после копирования / вставки ExpressionVisitor вам, вероятно, понадобится не более 10 строк кода без выражения; -)

Надеюсь, это поможет

1 голос
/ 12 августа 2016

Хотя деревья выражений - это весело, разве в этом случае не будет простым решением использовать OrderBy, а не ThenBy?

  • OrderBy является расширением IQueryable и возвращает IOrderedQueryable.
  • ThenBy является расширением IOrderedQueryable и возвращает IOrderedQueryable.

Так что, если у вас есть IQueryable (как в вашем случае выше, где запрос является IQueryable), и вы хотите применить к нему начальный порядок, используйте OrderBy. ThenBy предназначен только для применения дополнительного заказа к уже упорядоченному запросу.

Если у вас есть какой-либо результат LINQ, но вы не уверены, является ли он IQueryable или IOrderedQueryable и хотите применить к нему дополнительную фильтрацию, вы можете сделать два метода, например:

 static IOrderedQueryable<T, TKey> ApplyAdditionalOrdering<T, TKey>(this IOrderedQueryable<T, TKey> source, Expression<Func<T, TFilter>> orderBy)
        {
            return source.ThenBy(orderBy);
        }

И

static IOrderedQueryable<T, TKey> ApplyAdditionalOrdering<T, TKey>(this IQueryable<T> source, Expression<Func<T, TFilter>> orderBy)
        {
            return source.OrderBy(orderBy);
        }

Компилятор определит правильный для вызова на основе типа времени компиляции вашего объекта запроса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...