Gert Arnold Gert Arnold - 3 months ago 15
C# Question

When is ObjectQuery really an IOrderedQueryable?

Applied to entity framework, the extension methods

Select()
and
OrderBy()
both return an
ObjectQuery
, which is defined as:

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


The return type of
Select()
is
IQueryable<T>
and that of
OrderBy
is
IOrderedQueryable<T>
. So you could say that both return the same type but in a different wrapper. Luckily so, because now we can apply
ThenBy
after
OrderBy
was called.

Now my problem.

Let's say I have this:

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


This gives me an
IQueryable<Plot>
, which is an
ObjectQuery<Plot>
. But it is also an IOrderedQueryable:

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


But still:

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


When I do:

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


It compiles, but gives a runtime exception:


Expression of type '
IQueryable`1[Plot]
' cannot be used for parameter of type
'IOrderedQueryable`1[Plot]
' of method '
IOrderedQueryable`1[Plot] ThenBy[Plot,Nullable`1](IOrderedQueryable`1[Plot], Expressions.Expression`1[System.Func`2[Plot,System.Nullable`1[System.Int32]]])
'


The cast is carried out (I checked), but the parameter of
ThenBy
is still seen as IQueryable (which puzzles me a bit).

Now suppose some method returns an
ObjectQuery<Plot>
to me as
IQueryable<Plot>
(like
Select()
). What if I want to know whether it is safe to call
ThenBy
on the returned object. How can I figure it out if the
ObjectQuery
is "real" or a "fake"
IOrderedQueryable
without catching exeptions?

Answer

Expression Trees are genuinely good fun! (or perhaps I'm a little bit of a freak) and will likely become useful in many a developer's future if Project Roslyn is anything to go by! =)

In your case, simple inherit from MSDN's ExpressionVisitor, and override the VisitMethodCall method in an inheriting class with something to compare m.MethodInfo with SortBy (i.e. if you're not too fussy simply check the name, if you want to be fussy use reflection to grab the actual SortBy MethodInfo to compare with.

Let me know if/what you need examples of, but honestly, after copy/pasting the ExpressionVisitor you'll probably need no more than 10 lines of non-expression-tree code ;-)

Hope that helps

Comments