ObjectQuery什么时候真的是IOrderedQueryable?

时间:2012-01-26 20:50:37

标签: c# linq entity-framework-4 interface

应用于实体框架,扩展方法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而没有捕捉到exeptions,我怎么能搞清楚?

2 个答案:

答案 0 :(得分:2)

表达树真的很有趣! (或者我可能有点怪胎)如果Project Roslyn有任何意义,很可能会成为很多开发人员的未来! =)

在您的情况下,简单地继承自MSDN的ExpressionVisitor,并覆盖继承类中的VisitMethodCall方法,并将m.MethodInfoSortBy进行比较(即,如果您'不要太挑剔只需检查名称,如果你想挑剔使用反射来抓住实际的SortBy MethodInfo进行比较。

让我知道你/你需要什么样的例子,但老实说,在复制/粘贴ExpressionVisitor之后,你可能需要不超过10行的非表达式树代码; - )

希望有所帮助

答案 1 :(得分:1)

尽管表达树很有趣,但在这种情况下,简单的解决方案是使用OrderBy而不是ThenBy吗?

  • OrderByIQueryable的附加信息并返回IOrderedQueryable
  • ThenByIOrderedQueryable的附加信息并返回IOrderedQueryable

因此,如果你有一个IQueryable(如上面的情况,查询是一个IQueryable)并且你想对它应用初始排序,请使用OrderByThenBy仅用于对已排序的查询应用其他排序。

如果你有某种类型的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);
        }

编译器将根据查询对象的编译时类型找出要调用的正确函数。