3 votes

Méthode générique .net avec paramètres IQueryable<T> et Expression<Func<T, T>>

Je souhaite créer une méthode générique pour cette fonction et envoyer la classe de l'utilisateur et la clause where comme paramètres.

public void Update(where clause, User user) {}

Mais je n'arrive pas à trouver la bonne voie.

ctx.Users.Where(x => x.Id == 10)
         .Update(x => new User() { Name = "Jack" });

La déclaration de la méthode est la suivante :

public static int Update<T>(this IQueryable<T> query, Expression<Func<T, T>> updateFactory) where T : class;

0voto

Yacoub Massad Points 16759

Si vous transmettez un User par exemple, le Update ne serait pas en mesure de savoir quelles propriétés mettre à jour (par exemple, doit-elle toutes les mettre à jour ? Ou celles dont les valeurs ne sont pas par défaut ? Que se passe-t-il si une propriété a été intentionnellement fixée à une valeur par défaut ?)

Vous devez passer un Expression<Func<T, T>> qui contient une expression d'initialisation d'un membre, par exemple x => new User() { Name = "Jack" } .

Les expressions sont des codes sous forme de données. En interne, le cadre analyserait l'expression et verrait quelles propriétés sont censées être mises à jour. Dans le cas de l'exemple, il verra que seule la propriété Name était destiné à être mis à jour.

En ce qui concerne l'expression where, vous devez passer Expression<Func<User,bool>> . Votre méthode ressemblerait donc à ceci :

public void Update(
    Expression<Func<User,bool>> condition,
    Expression<Func<User,User>> updateFactory)
{
    ctx.Users
       .Where(condition)
       .Update(updateFactory);
}

Vous pouvez l'utiliser comme suit :

Update(x => x.Id == 10, x => new User() { Name = "Jack" });

EDIT :

Si vous disposez d'un moyen de déterminer les propriétés à mettre à jour, vous pouvez construire l'expression comme suit :

public static void Update(
    Expression<Func<User, bool>> condition,
    User user,
    PropertyInfo[] propertiesToUpdate)
{
    Expression<Func<User, User>> updateFactory =
        Expression.Lambda<Func<User, User>>(
            Expression.MemberInit(
                Expression.New(typeof (User)),
                propertiesToUpdate
                    .Select(prop =>
                        Expression.Bind(
                            prop.SetMethod,
                            Expression.Constant(prop.GetValue(user))))),
            Expression.Parameter(typeof(User), "u"));

    ctx.Users
        .Where(condition)
        .Update(updateFactory);
}

Si vous n'avez que des noms de propriétés, vous pouvez utiliser la fonction Type.GetProperty pour obtenir la méthode PropertyInfo .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X