2017-09-14 11 views
0

Comment est-il possible de filtrer les données en fonction d'un ensemble de filtres ou d'expressions à utiliser avec l'opération or dans la clause where?Filtrer les données avec plusieurs clauses complexes jointes à l'opération OU dans la fonction

Par exemple, il y a une classe:

class DTOFilter 
{ 
    public string Domain { get; set; } 
    public string Mobile { get; set; } 
} 

Il est nécessaire de filtrer Users liste en fonction de la liste des filtres suivant ainsi:

u=> 
(u.Email.Contains(filters[0].Domain) && u.PhoneNumber.StartsWith(filters[0].Mobile)) || 
(u.Email.Contains(filters[1].Domain) && u.PhoneNumber.StartsWith(filters[1].Mobile)) || 
... 

Il est évident que cela devrait être construire automatiquement dans former comme:

db.Users.Where(filters.Filter<Users, DTOFilter>(
         (u, f) => u.Email.Contains(f.Domain) 
           && u.PhoneNumber.StartsWith(f.Mobile)) 
       .Or()) 

Répondre

1

Pour effectuer cette tâche, il est nécessaire d'implémenter deux Fonctions:

  1. Or expression_table fonction
  2. filtre fonction split de données

ou la fonction passe par une collection d'expressions et les rejoint dans une expression Or comme (((expression1 or expression2) or expression3) or expression4)

public static Expression<Func<T, bool>> Or<T>(
    this IEnumerable<Expression<Func<T, bool>>> source) 
    { 
     var expressions = source.ToList(); 
     if (expressions.Count == 0) 
      return x => false; 

     var orExpression = expressions 
      .Select(e => e.Body) 
      .Aggregate((a, b) => Expression.OrElse(a, b)); 
     var parameter = expressions.First().Parameters.First(); 
     return Expression.Lambda<Func<T, bool>>(orExpression, parameter); 
    } 

Cette La fonction peut déjà être utilisée si les filtres sont déjà des expressions valides.

La fonction de partage de données de filtre doit multiplier l'expression du sélecteur et remplacer dans le paramètre d'expression de résultat par la valeur exacte de l'objet. population de données de filtrage se fait dans la fonction:

public static IEnumerable<Expression<Func<T, bool>>> Filter<T, TData>(
    this IEnumerable<TData> data, 
    Expression<Func<T,TData, bool>> selector) 
{ 
    var parameter = selector.Parameters.First(p => p.Type.IsAssignableFrom(typeof(T))); 

    return data.Select(item => Expression.Lambda<Func<T, bool>>(
     new DataVisitor<TData>(item).Visit(selector.Body), parameter)); 
} 

mise en œuvre des visiteurs suivante permet de remplacer le paramètre avec la valeur exacte:

public class DataVisitor<T> : ExpressionVisitor 
{ 
    private readonly ConstantExpression _data; 

    public DataVisitor(T dataItem) 
    { 
     _data = Expression.Constant(dataItem); 
    } 

    protected override Expression VisitParameter(ParameterExpression node) 
    { 
      return node.Type.IsAssignableFrom(typeof(T)) 
        ? _data : base.VisitParameter(node); 
    } 
} 

La construction d'expression est une expression lambda correcte qui peut être analysé par l'EF analyseur d'arbre d'expression.