如何使用具有多个属性的 collection 在 Dapper 中进行过滤?
How to filter in Dapper using a collection with multiple properties?
我对 Dapper 有点陌生,我正在尝试寻找一种干净的方法将过滤器参数传递给 SQL 查询 collection 有多个 属性。
我的 collection 看起来像这样:
[{
Prop1: 'A Value 1',
Prop2: 'B Value 1'
},
{
Prop1: 'A Value 2',
Prop2: 'B Value 2'
}]
这应该导致 SQL 查询看起来像这样:
select *
from SampleTable
where
([ColumnA]='A Value 1' and [ColumnB]='B Value 1')
or ([ColumnA]='A Value 2' and [ColumnB]='B Value 2')
注意:如下所示的内容将不起作用,因为 PropA 和 PropB 这两个属性需要一起过滤。
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();
您可以使用以下帮助程序动态生成过滤器字符串 class:
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));
}
}
用法:
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();
查询字符串如下所示:
select *
from SampleTable
where ( [ColumnA] = 'A Value 1' AND [ColumnB] = 'A Value 2' )
OR ( [ColumnA] = 'B Value 1' AND [ColumnB] = 'B Value 2' )
将过滤器建模为 class:
class MyFilterDefinition
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
使用 DapperQueryBuilder 构建动态条件就像这样简单:
var myOptions = new List<MyFilterDefinition>()
{
new MyFilterDefinition() { Prop1 = "A Value 1", Prop2 = "B Value 1" },
new MyFilterDefinition() { Prop1 = "A Value 2", Prop2 = "B Value 2" }
}
var query = cn.QueryBuilder($@"
select *
from SampleTable
/**where**/");
// by default multiple filters are combined with AND, so change to OR
query.FiltersType = Filters.FiltersType.OR;
foreach (var option in myOptions)
query.Where($"[ColumnA] = {option.Prop1} AND [ColumnB] = {option.Prop2}");
var results = query.Query<YourPOCO>();
最终结果是这样的:
select *
from SampleTable
where ([ColumnA]=@p0 AND [ColumnB]=@p1) OR ([ColumnA]=@p2 AND [ColumnB]=@p3)
用各自的参数@p0 = 'A Value 1',等等
免责声明:我是 DapperQueryBuilder 的作者
我对 Dapper 有点陌生,我正在尝试寻找一种干净的方法将过滤器参数传递给 SQL 查询 collection 有多个 属性。
我的 collection 看起来像这样:
[{
Prop1: 'A Value 1',
Prop2: 'B Value 1'
},
{
Prop1: 'A Value 2',
Prop2: 'B Value 2'
}]
这应该导致 SQL 查询看起来像这样:
select *
from SampleTable
where
([ColumnA]='A Value 1' and [ColumnB]='B Value 1')
or ([ColumnA]='A Value 2' and [ColumnB]='B Value 2')
注意:如下所示的内容将不起作用,因为 PropA 和 PropB 这两个属性需要一起过滤。
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();
您可以使用以下帮助程序动态生成过滤器字符串 class:
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));
}
}
用法:
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();
查询字符串如下所示:
select *
from SampleTable
where ( [ColumnA] = 'A Value 1' AND [ColumnB] = 'A Value 2' )
OR ( [ColumnA] = 'B Value 1' AND [ColumnB] = 'B Value 2' )
将过滤器建模为 class:
class MyFilterDefinition
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
使用 DapperQueryBuilder 构建动态条件就像这样简单:
var myOptions = new List<MyFilterDefinition>()
{
new MyFilterDefinition() { Prop1 = "A Value 1", Prop2 = "B Value 1" },
new MyFilterDefinition() { Prop1 = "A Value 2", Prop2 = "B Value 2" }
}
var query = cn.QueryBuilder($@"
select *
from SampleTable
/**where**/");
// by default multiple filters are combined with AND, so change to OR
query.FiltersType = Filters.FiltersType.OR;
foreach (var option in myOptions)
query.Where($"[ColumnA] = {option.Prop1} AND [ColumnB] = {option.Prop2}");
var results = query.Query<YourPOCO>();
最终结果是这样的:
select *
from SampleTable
where ([ColumnA]=@p0 AND [ColumnB]=@p1) OR ([ColumnA]=@p2 AND [ColumnB]=@p3)
用各自的参数@p0 = 'A Value 1',等等
免责声明:我是 DapperQueryBuilder 的作者