Как я могу повторно использовать выражения в операторах LINQ?
Мне нравится повторно использовать выражения по причинам DRY, но как я могу повторно использовать выражения в инструкции LINQ?
например.
У меня
public static class MyExpressions {
public static Expression<Func<Product,bool>> IsAGoodProduct() {
return (p) => p.Quality>3;
}
}
И хотел бы использовать это в операторах LINQ, поэтому
var goodProds = from p in dataContext.Products
where ????? // how do I use IsAGoodProduct here?
select p;
Конечно, я мог бы использовать функцию IQueryableExtension.Where, но это сделало бы объединения и другие функции более уродливыми для более сложных запросов.
Возможно ли это или это ограничение LINQ?
Ответы
Ответ 1
Если вы перейдете из синтаксического сахара LINQ, это возможно:
var goodProds = dataContext.Products.Where(MyExpressions.IsAGoodProduct());
Без него это невозможно.
Ничего не мешает вам смешивать два стиля для создания одного запроса.
Пример:
var goodProds = from p in dataContext.Products
.Where(MyExpressions.IsAGoodProduct())
group p by p.Category into g
select new {Category = g.Key, ProductCount = g.Group.Count()};
Ответ 2
У меня была та же проблема, и я хотел сохранить возможность использовать методы расширения в синтаксисе запроса (как с обычными поддерживаемыми функциями...). Решением может быть эта библиотека (спойлер: я автор).
Вы просто реализуете метод повторного использования дважды, один раз для общего использования и один раз для запросов.
public static class MyFunctions {
[InjectLambda]
public static bool IsAGoodProduct(Product product) {
return product.Quality>3;
}
public static Expression<Func<Product,bool>> IsAGoodProduct() {
return (p) => p.Quality>3;
}
}
Фактический запрос может выглядеть так, как ожидалось.
var goodProds = from p in dataContext.Products.ToInjectable()
where p.IsAGoodProduct()
select p;
ToInjectable
создает облегченный прокси, который заменяет IsAGoodProduct
метода IsAGoodProduct
(если помечен соответствующим образом) на желаемое лямбда-выражение. Таким образом, вы можете использовать методы расширения везде, где в запросе работают параметризованные методы.
Ответ 3
У нас была та же проблема. Он не поддерживается из коробки, и это большая проблема для приложений LOB. Я закончил писать статью кода-проекта о повторном использовании выражений LINQ, включая очень маленькую утилиту LinqExpressionPrjection, которая позволяет повторно использовать в проекциях (в том числе и анонимные).
Найти статью здесь.
Вы можете получить сборку для повторного использования проекции как пакет nuget, а источник находится на CodePlex.
С момента вашего сообщения прошло некоторое время. Надеюсь, это по-прежнему полезно для вас. Если нет, возможно, для других, читающих эту тему.
Ответ 4
Кстати, я столкнулся с этой полезной статьей, в которой объясняется, как вы можете создавать динамические запросы LINQ, которые ссылаются на функции Expression используя пользовательский метод расширения ToExpandable(). Предоставленное решение может использоваться в различных частях запроса LINQ Query, сохраняя при этом использование синтаксиса понимания вместо того, чтобы прибегать к синтаксису лямбда.