Comment créer une condition dynamique en utilisant Expression Tree

c# c#-4.0 entity-framework expression-trees linq

Question

Veuillez considérer ce code:

System.Linq.Expressions.Expression<Func<tbl, bool>> exp_details = r => r.ID_Master == Id &&
r.Year == Year &&
r.Month == Month ;

Je veux écrire une fonction qui attend un argument, puis récupérer des données de ma base de données. Le problème est que je veux créer un exemple dynamique condition.dor si je passe l'argument IsDeleted avec true valeur true . Je veux ajouter r.IsDeleted == true; à exp_details . Comment puis-je faire ceci?

Réponse acceptée

La clé pour ce faire consiste à utiliser un ExpressionVisitor qui parcourt l'expression donnée et (éventuellement dans une sous-classe) permet de remplacer les éléments reconnus par d'autres que vous spécifiez. Dans mon cas, cela a été fait pour ORM (NHibernate). C'est ce que j'utilise: (j'ajouterai des références à ma réponse plus tard)

public class ParameterAssignAndReplacer : ExpressionVisitor
{
    private readonly ParameterExpression _source;
    private readonly ConstantExpression _target;

    internal ParameterAssignAndReplacer(ParameterExpression source, ConstantExpression target)
    {
        _source = source;
        _target = target;
    }

    protected override Expression VisitParameter(ParameterExpression node)
    {
        return node.Name == _source.Name ?
            base.VisitConstant(_target) :
            base.VisitParameter(node);
    }
}

Et..

public static class ExpressionExtensions
{
    public static Expression<Func<TArg2, TResult>> AssignAndReduce<TArg1, TArg2, TResult>(
        this Expression<Func<TArg1, TArg2, TResult>> func,
        TArg1 parameter)
    {
        var exprBody = func.Body;
        var assignedParameter = Expression.Constant(parameter, typeof(TArg1));
        exprBody = new ParameterAssignAndReplacer(func.Parameters[0], assignedParameter).Visit(exprBody);
        return Expression.Lambda<Func<TArg2, TResult>>(exprBody, func.Parameters[1]);
    }
}

Les deux classes peuvent être étendues à votre scénario spécifique. Pour que cela soit pertinent pour le code que vous avez posté (j'utilise uniquement IsDeleted comme paramètre pour plus de simplicité):

public class SomeClass
{
    Expression<Func<tbl, bool, bool>> _templateExpression =
       (tbl r, bool isDeleted) => r.ID_Master == 5 && r.Year == 2008 && r.Month == 12 && r.IsDeleted == isDeleted;

    public Expression<Func<tbl, bool>> Foo(bool IsDeleted)
    {
        return _templateExpression.AssignAndReduce(IsDeleted);
    }
}

En ce qui concerne les références, la plupart de ce que j’ai appris sur ce sujet provient de la réponse "Expressions" de Marc Gravell [bien que de nombreux autres utilisateurs m’aient aidé à comprendre :-)]


Réponse populaire

vous ne pouvez pas utiliser le corps d'une instruction pour Linq Expression, envisagez plutôt d'utiliser Predicate

        var exp_details = new Predicate<tbl>(r =>
        {
            bool result == Id && r.Year == Year && r.Month == Month;
            if(IsDeleted != null)
            {
                result &= r.IsDeleted == IsDeleted;
            }
            return result;
        });

l'expression la plus Linq Func <T, bool> peut être remplacée par Predicate <T> .

Pour générer une cause WHERE dynamique à l’aide d’une expression "simple" linq.

IQueryable<tbl> query = ent.tbl.Where(r => r.ID_Master == Id && r.Year == Year);
//customize query
if(IsDeleted != null){
  query = query.Where(r => r.IsDeleted == IsDeleted);
}
//execute the final generated query
var result = query.FirstOrDefault();

cela créera où cause de IQueryable<T> . Linq est assez intelligent pour les requêtes complexes.



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi