2017-10-19 24 views
2

Je suis un peu nouveau à Dapper et j'essaie de trouver un moyen propre de passer un paramètre de filtre à SQL Query pour une collection avec plus d'une propriété.Comment filtrer dans Dapper en utilisant une collection avec plusieurs propriétés?

Ma collection ressemble à ceci:

[{ 
    Prop1: 'A Value 1', 
    Prop2: 'B Value 1' 
}, 
{ 
    Prop1: 'A Value 2', 
    Prop2: 'B Value 2' 
}] 

Ce qui devrait se traduire par une recherche quelque chose comme requête SQL ceci:

select * 
from SampleTable 
where 
([ColumnA]='A Value 1' and [ColumnB]='B Value 1') 
or ([ColumnA]='A Value 2' and [ColumnB]='B Value 2') 

Note: Quelque chose comme ce qui est indiqué ci-dessous ne fonctionnera pas parce que les deux propriétés PropA et PropB doivent filtrer ensemble.

string query = @"select * 
       from SampleTable 
       where [ColumnA] in (@PropA_Value) 
       and [ColumnB] in (@PropB_Value)" 

con.Query<T>(query, new{PropA_Value = PropA,PropB_Value = PropB}).AsList(); 

Répondre

0

Vous pouvez générer des chaînes de filtre dynamiquement en utilisant la classe d'aide suivante:

public static class DapperHelper 
    { 
     private const string SingleTupleFormat = " [{0}] = '{1}' {2}"; 
     private const string AndString = "AND"; 
     private const string OrString = "OR"; 

     private static string ToSqlTuple(List<Dictionary<string, string>> filters) 
     { 
      string filterParam = string.Empty; 
      foreach (var filter in filters) 
      { 
       //Construct single tuple 
       string tuple = filter.ToList().Aggregate(string.Empty, 
       (current, pair) => current + String.Format(SingleTupleFormat, pair.Key, pair.Value, AndString)); 

       //Concatenate tuples by OR, string.Format to combine the different filters 
       filterParam += string.Format(" ({0}) {1}", tuple.TrimEnd(AndString), OrString); 
      } 
      return filterParam.TrimEnd(OrString); 
     } 

     public static string TrimEnd(this string source, string value) 
     { 
      if (!source.EndsWith(value)) 
       return source; 

      return source.Remove(source.LastIndexOf(value)); 
     } 
    } 

Utilisation:

string query = @"select * 
       from SampleTable 
       where @where"; 

List<Dictionary<string, string>> filters = new List<Dictionary<string, string>>() { 
       new Dictionary<string, string>(){{"ColumnA", "A Value 1"},{"ColumnB", "A Value 2"}}, 
       new Dictionary<string, string>(){{"ColumnA", "B Value 1"},{"ColumnB", "B Value 2"}} 
      }; 

var tuple = DapperHelper.ToSqlTuple(filters); 
query = query.Replace("@where", string.IsNullOrEmpty(tuple) ? "1=1" : tuple); //Use 1=1 if tuple is empty or null 

var data = con.Query<T>(query).AsList(); 

chaîne de requête ressemble à:

select * 
from SampleTable 
where ([ColumnA] = 'A Value 1' AND [ColumnB] = 'A Value 2') 
    OR ([ColumnA] = 'B Value 1' AND [ColumnB] = 'B Value 2') 
+3

Merci Je pense que ce est vraiment utile. Bien que n'étant pas une solution intégrée dans Dapper, c'est certainement quelque chose qui est réutilisable et une bonne solution. Je pense que l'autre chose à garder à l'esprit avec cette solution est de vérifier l'injection SQL puisque nous n'utilisons pas la méthode Dapper par défaut pour passer les paramètres. – m0g

+0

Ouais, ma solution est juste de montrer comment construire la chaîne de filtrage sans tenir compte d'autres avantages tels que l'injection SQL. – Yared

+0

Ce lien mai également aider; https://github.com/tmsmith/Dapper-Extensions/wiki/Predicates voir la section 'Prédicats composés multiples (groupe de prédicats)' – Yared