考虑这些扩展:
public static IOrderedEnumerable<Thing> OrderByDateAndNumber(this IEnumerable<Thing> source)
{
return source.OrderByDescending(x => x.ThingDate).ThenByDescending(x => x.ThingNumber);
}
public static IOrderedQueryable<Thing> OrderByDateAndNumber(this IQueryable<Thing> source)
{
return source.OrderByDescending(x => x.ThingDate).ThenByDescending(x => x.ThingNumber);
}
这有效:
var x = context.Things.OrderByDateAndNumber().ToList();
但这不是:
var y = context.Widgets.Select(w => w.Things.OrderByDateAndNumber().Count());
制作例外:
[NotSupportedException:LINQ to Entities无法识别方法'System.Linq.IOrderedEnumerable
1[Namespace.Thing] OrderDateAndNumber(System.Collections.Generic.IEnumerable
1 [Namespace.Thing])'方法,并且此方法无法转换为商店表达式。]
我认为C#代码无法转换为商店表达式。我不明白为什么它在第一个实例中起作用(假设这是通过我的扩展调用仅调用支持的OrderBy
方法)而不是在第二个我试图将它合并到一个语句中它使用导航属性,即w.Things
)
答案 0 :(得分:2)
如果你删除扩展方法的语法糖并使用经典方法调用,那就很明显了:
这有效:
var x = LinqExtensions.OrderByDateAndNumber(context.Things).ToList();
但这不是:
var y = context.Widgets.Select(w =>
LinqExtensions.OrderByDateAndNumber(w.Things)).Count());
第一种方法解析为接受IQueryable
的重载,它只返回附加了排序表达式的IQueryable
。
另一种说法是:在第一个代码段中,OrderByDateAndNumber
在外面表达式。
在第二个代码段中,OrderByDateAndNumber
解析为IEnumerable
重载,因为导航属性w.Things
(可能)是ICollection
。另外OrderByDateAndNumber
现在在表达式中,因此是应该转换为SQL的构造的一部分。
答案 1 :(得分:1)
简单地说。
Context.Things
上下文在您的c#方法范围内被引用,该范围有权访问您的扩展方法。
w => w.Things
W 只是一个lambda引用,它将在Linq To实体程序集中稍后进行评估,该程序集无法访问Extension方法范围。
我发现LinqKit对这些具有“扩展”功能的情况非常有帮助。
它的所有功能是在将扩展方法发送到Linq-to-Entities之前将其翻译。