Когда ObjectQuery действительно является IOrderedQueryable?
Применительно к сущности, методы расширения 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 ответа
Деревья выражений - действительно хорошее развлечение! (или, может быть, я немного ненормальный) и, вероятно, станет полезным для многих разработчиков в будущем, если Project Roslyn что-нибудь придет! знак равно
В вашем случае простое наследование от MSDN ExpressionVisitor и переопределение VisitMethodCall
метод в наследующем классе с чем-то, чтобы сравнить m.MethodInfo
с SortBy
(то есть, если вы не слишком суетливы, просто проверьте имя, если вы хотите быть суетливым, используйте отражение, чтобы взять фактическое SortBy MethodInfo для сравнения.
Дайте мне знать, если вам нужны примеры, но, если честно, после копирования / вставки ExpressionVisitor вам, вероятно, понадобится не более 10 строк кода без выражения;-)
надеюсь, это поможет
Хотя деревья выражений - это весело, разве в этом случае не будет простым решением использовать 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);
}
Компилятор определит правильный для вызова на основе типа времени компиляции вашего объекта запроса.