Подтвердить что ты не робот

Как "позволить" в выражении лямбды?

Как я могу переписать этот запрос linq для Entity on с помощью выражения лямбда? Я хочу использовать ключевое слово 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 для каждого элемента, в то время как в стиле Query, о котором я упоминал, пусть выражение предотвращает вычисление среднего числа раз.

4b9b3361

Ответ 1

Итак, вы можете использовать синтаксис метода расширения, который будет включать в себя одно лямбда-выражение больше, чем вы сейчас используете. Нет let, вы просто используете многострочный лямбда и объявляете переменную:

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);

Ответ 2

В принципе, вам нужно использовать 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 создает новый анонимный тип для объекта в вашей коллекции, он потребляет много памяти с большими коллекциями  ...

Посмотрите сюда подробности: Пусть в цепных методах расширения

Ответ 3

Другим вариантом является определение этого метода расширения:

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));

Ответ 4

Мы можем избежать накладных расходов лямбды, используемой во всех остальных ответах, с помощью встроенного объявления:

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);