如何使用lambda表达式将此linq查询重写为Entity on? 我想在我的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,而在我提到的查询样式中, let 表达式阻止多次计算平均值。
答案 0 :(得分:45)
因此,您可以使用扩展方法语法,这将涉及比您当前使用的更多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);
答案 1 :(得分:24)
基本上,您需要使用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);
警告,请注意这些结构。使用let会在集合中为每个对象创建一个新的匿名类型,它会占用大量集合的大量内存 ...
在此查看详细信息: Let in chained extension methods
答案 2 :(得分: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));
答案 3 :(得分:1)
我们可以通过内联输出声明来避免其他所有答案中使用的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);