Expresiones de predicado reutilizables en LINQ para consultas de entidades

Un cierto conjunto de criterios que se presenta en muchas consultas diferentes a lo largo de nuestra aplicación se ha vuelto cada vez más complejo. Para evitar la duplicación de este código, quiero dividir estos criterios en un método que devuelve las condiciones como una expresión que a su vez se puede aplicar cuando sea necesario:

public Expression<Func> GetComplexPredicate() { // complex predicate is returned as an Expression: return c => ... } 

Reutilizado como tal:

 var result = repository.Invoice.Where(GetComplexPredicate()) 

Sin embargo, la siguiente statement no se comstackrá, ya que c.Invoice es solo una ICollection .

 var result = repository.Customer .Where(c => c.Country == "US" && c.Invoice.Any(GetComplexPredicate())) 

¿Es posible de alguna manera usar la expresión como esta?

Hay dos partes a esta pregunta:

¿Cómo uso expresiones de predicado en las propiedades de navegación dentro de una consulta L2E?

L2E permite el uso del método de extensión AsQueryable dentro de una consulta. Esto significa que puedo convertir el ICollection a un IQueryable y aplicar la expresión de predicado. Hasta ahora tan bueno. Sin embargo, podría comstackrse, pero aún así no se ejecutará, ya que L2E no sabrá qué hacer con la expresión predefinida del método GetComplexPredicate. Esto nos lleva a:

¿Cómo combino varias expresiones de predicado separadas en una?

El LINQKit enormemente útil puede combinar fácilmente varios predicados en una expresión usando PredicateBuilder . Con el método Expand de LINQKit y el AsQueryable antes mencionado, finalmente podemos llegar a una statement que se comstackrá y ejecutará a la perfección :

 // build the entire predicate beforehand (PredicateBuilder + AsQueryable): var complexPredicate = GetComplexPredicate(); var condition = PredicateBuilder.True() .And(c => c.Country == "US") .And(c => c.Invoice.AsQueryable().Any(complexPredicate)); // apply criteria to query (using Expand): var result = repository.Customer.Where(condition.Expand()).ToList();