应用于实体框架,扩展方法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,我怎么能搞清楚?
答案 0 :(得分:2)
表达树真的很有趣! (或者我可能有点怪胎)如果Project Roslyn有任何意义,很可能会成为很多开发人员的未来! =)
在您的情况下,简单地继承自MSDN的ExpressionVisitor,并覆盖继承类中的VisitMethodCall
方法,并将m.MethodInfo
与SortBy
进行比较(即,如果您'不要太挑剔只需检查名称,如果你想挑剔使用反射来抓住实际的SortBy MethodInfo进行比较。
让我知道你/你需要什么样的例子,但老实说,在复制/粘贴ExpressionVisitor之后,你可能需要不超过10行的非表达式树代码; - )
希望有所帮助
答案 1 :(得分:1)
尽管表达树很有趣,但在这种情况下,简单的解决方案是使用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);
}
编译器将根据查询对象的编译时类型找出要调用的正确函数。