尝试在实体框架

时间:2017-02-02 11:00:20

标签: c# linq-to-entities

考虑这些扩展:

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

2 个答案:

答案 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之前将其翻译。