44

如何使用 lambda 表达式将此 linq 查询重写为 Entity?
我想在我的 lambda 表达式中使用let关键字或等效关键字。

var results = from store in Stores
              let AveragePrice =  store.Sales.Average(s => s.Price)
              where AveragePrice < 500 && AveragePrice > 250

对于一些类似的问题,例如我的问题下评论的内容,建议

.Select(store=> new { AveragePrice = store.Sales.Average(s => s.Price), store})

它将计算每个项目的 AveragePrice,而在我提到的查询样式中,表达式防止多次计算平均值。

4

4 回答 4

48

因此,您可以使用扩展方法语法,这将涉及比您当前使用的更多的 lambda 表达式。没有let,您只需使用多行 lambda 并声明一个变量:

var results = Stores.Where(store => 
{
    var averagePrice = store.Sales.Average(s => s.Price);
    return averagePrice > 250 && averagePrice < 500;
});

请注意,我更改了平均价格比较,因为您的将永远不会返回任何结果(超过 500 且少于 250)。

替代方案是

var results = Stores.Select(store => new { Store = store, AveragePrice = store.Sales.Average(s => s.Price})
    .Where(x => x.AveragePrice > 250 && x.AveragePrice < 500)
    .Select(x => x.Store);
于 2012-02-11T13:02:28.790 回答
27

基本上,您需要使用 Select 和匿名类型将平均值添加到您的对象,然后是您的语句的其余部分。

未经测试,但应该如下所示:

Stores.Select(
    x => new { averagePrice = x.Sales.Average(s => s.Price), store = x})
.Where(y => y.averagePrice > 500 && y.averagePrice < 250)
.Select(x => x.store);

警告:这适用于 Linq-to-Entities,但要小心 Linq-to-Objects 中的这些构造。使用let为集合中的每个对象创建一个新的匿名类型,它会在大型集合中消耗大量内存。

在这里查看详细信息: 让链式扩展方法

于 2012-02-11T13:03:14.087 回答
4

另一种选择是定义此扩展方法:

public static class Functional
{
    public static TResult Pipe<T, TResult>(this T value, Func<T, TResult> func)
    {
        return func(value);
    }
}    

然后像这样编写您的查询:

var results = Stores
    .Where(store => store.Sales.Average(s => s.Price)
        .Pipe(averagePrice => averagePrice < 500 && averagePrice > 250));
于 2013-08-07T17:35:43.383 回答
1

我们可以通过 inline out 声明避免在所有其他答案中使用的 lambda 开销:

public static class FunctionalExtensions
{
    public static T Assign<T>(this T o, out T result) =>
        result = o;
}

像这样称呼它

var results = Stores
    .Where(store => store.Sales
        .Average(s => s.Price)
        .Assign(out var averagePrice) < 500 && averagePrice > 250);
于 2019-10-05T15:12:28.613 回答