Cree IQueryable.Any con árboles de expresiones para consultas LINQ

c# expression-trees

Pregunta

Estoy creando una cláusula "WHERE" de SQL de forma dinámica utilizando la clase System.Linq.Expressions.Expression. Funciona bien para cláusulas simples, por ejemplo, para agregar la cláusula "PhaseCode = X", hago lo siguiente:

var equalTarget = Expression.Constant(phaseCode, typeof(int?));
var phaseEquals = Expression.Equal(Expression.PropertyOrField(projParam, "PhaseCode"), equalTarget);

Sin embargo, ahora estoy tratando de construir una expresión que devuelva el registro si un proyecto ha sido asignado a un grupo en particular. Proyecto y Grupo tiene una relación de muchos a muchos. Sin la expresión árboles, lo haría de la siguiente manera:

db.Projects.Where(p => .... && p.GroupsAssigned.Any(g => g.ID == groupId))

Sin embargo, parece que no puedo encontrar una manera de expresar eso con la clase de Expresión. En realidad hay dos cosas que no puedo entender:

  • Cómo atravesar las relaciones entre tablas.
  • Cómo hacer x.Any ()

Cualquier ayuda es muy apreciada.

Respuesta aceptada

Llamar a un método de extensión, como Enumerable.Any o Queryable.Any , es simplemente una llamada de método estático en la secuencia y la expresión lambda que creó para la cláusula WHERE . Puedes usar Expression.Call para hacer esto:

// for Enumerable.Any<T>(IEnumerable<T>,Predicate<T>)
var overload = typeof(Enumerable).GetMethods("Any")
                                 .Single(mi => mi.GetParameters().Count() == 2);
var call = Expression.Call(
    overload,
    Expression.PropertyOrField(projParam, "GroupsAssigned"),
    anyLambda);      

Para Queryable.Any<T> , Queryable.Any<T> esto en un método:

static Expression BuildAny<TSource>(Expression<Func<TSource, bool>> predicate)
{
    var overload = typeof(Queryable).GetMethods("Any")
                              .Single(mi => mi.GetParameters().Count() == 2);
    var call = Expression.Call(
        overload,
        Expression.PropertyOrField(projParam, "GroupsAssigned"),
        predicate);   

    return call;
}

Aunque parezca extraño que no puedas hacer esto a través de una consulta normal.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow