Construire IQueryable.Any avec des arbres d'expression pour les requêtes LINQ

c# expression-trees

Question

Je construis une clause SQL "WHERE" de manière dynamique à l'aide de la classe System.Linq.Expressions.Expression. Cela fonctionne bien pour les clauses simples, par exemple pour ajouter la clause "PhaseCode = X", je fais ce qui suit:

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

Cependant, j'essaie maintenant de créer une expression qui renverra l'enregistrement si un projet a été affecté à un groupe particulier. Le projet et le groupe ont une relation plusieurs à plusieurs. Sans les arbres d'expression, je le ferais comme suit:

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

Cependant, je n'arrive pas à trouver un moyen de l'exprimer avec la classe Expression. Il y a en fait deux choses que je ne peux pas comprendre:

  • Comment traverser les relations entre les tables
  • Comment faire x.Any ()

Toute aide est grandement appréciée.

Réponse acceptée

L'appel d'une méthode d'extension, comme Enumerable.Any ou Queryable.Any , est simplement un appel de méthode statique sur la séquence et l'expression lambda que vous avez créée pour la clause WHERE . Vous pouvez utiliser Expression.Call pour cela:

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

Pour Queryable.Any<T> , vous devrez l' Queryable.Any<T> dans une méthode:

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

Bien que cela semble étrange que vous ne puissiez pas le faire via une requête normale.



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow