如何使用Dapper构建动态参数化查询?

时间:2019-02-19 14:51:14

标签: c# .net dapper

如何使用dapper构建动态参数化查询?

我在KeyValuePair中有列及其值

例如

Key   | Value
------| -------
FName | Mohan
LName | O'reily
Gender| Male

我想使用dapper构建动态SQL语句并执行它,

    string statement = "SELECT * FROM Employee WHERE 1 = 1 ";
    List<KeyValuePair<string,string>> lst = new List<KeyValuePair<string,string>>();
    lst.Add(new KeyValuePair<string,String>("FName","Kim"));
    lst.Add(new KeyValuePair<string,String>("LName","O'reily"));
    lst.Add(new KeyValuePair<string,String>("Gender","Male"));
    foreach(var kvp in lst)
    {
        statement += " AND "+ kvp.Key +" = '"+ kvp.Value +"'";
    }
    using (var connection = _dataAccessHelper.GetOpenConnection())
    {
      try
      {
           //CommandDefinition cmd = new CommandDefinition(statement);

           var searchResult = await connection.QueryAsync<dynamic>(statement);

以上查询失败,因为查询中包含特殊字符。
我发现对于参数化语句CommandDefinition可以使用,

如何使用CommandDefinition执行以上语句而没有任何错误?

有没有更好的方法来构建动态sql语句?

4 个答案:

答案 0 :(得分:2)

不要将查询构建为文本。您可以使用Dapper SqlBuilder,它的内容如下:

List<KeyValuePair<string,string>> lst = new List<KeyValuePair<string,string>>();
lst.Add(new KeyValuePair<string,String>("FName","Kim"));
lst.Add(new KeyValuePair<string,String>("LName","O'reily"));
lst.Add(new KeyValuePair<string,String>("Gender","Male"));
var builder = new SqlBuilder();
var select = builder.AddTemplate("select * from Employee /**where**/");
foreach (var kvPair in lst)
{
    builder.Where($"{kvPair.Key} = @{kvPair.Key}", new { kvPair.Value });
}
using (var connection = _dataAccessHelper.GetOpenConnection())
{
    try
    {
        var searchResult = await connection.QueryAsync<dynamic>(select.RawSql, select.Parameters);
    }
    ...

您绝不要尝试自己转义参数,而应将其留给Dapper。然后,还将防止SQL注入。

答案 1 :(得分:1)

没有理由使用键值对列表来构建具有动态参数的SQL语句。您可以简单地在查询中放入占位符,例如@FName 从上面的示例中获取,并通过将匿名类型及其键与占位符相对应的键值传递给要用于查询的动态值,来提供这些占位符的值作为QueryAsync方法的第二个参数。

string statement = "SELECT * FROM Employee WHERE FName=@FName AND LName=@LName AND Gender=@Gender";
...
var searchResult = await connection.QueryAsync<dynamic>(statement, new { FName = "Kim", LName = "O'reily", Gender="Male" });

答案 2 :(得分:1)

DapperQueryBuilder 是Dapper SqlBuilder的替代方法,其工作方式如下:

List<KeyValuePair<string,string>> lst = new List<KeyValuePair<string,string>>();
lst.Add(new KeyValuePair<string,String>("FName","Kim"));
lst.Add(new KeyValuePair<string,String>("LName","O'reily"));
lst.Add(new KeyValuePair<string,String>("Gender","Male"));

using (var connection = _dataAccessHelper.GetOpenConnection())
{
    var query = connection.QueryBuilder($@"SELECT * FROM Employee");

    foreach(var kvp in lst)
        query.Where(${kvp.Key:raw} = {kvp.Value}";

    var searchResult = await query.QueryAsync<YourPOCO>();
}

输出为完全参数化的SQL(WHERE FName = @p0 AND LName = @p1 etc)。

您只需要知道使用raw修饰符插入的字符串不会作为参数传递(因为您不能将列作为参数传递),因此,应确保“键” (列名)是安全的。其他字符串(在您的情况下为值)看起来像常规(不安全)字符串插值,但它们会转换为参数。

免责声明:我是该库的作者之一

答案 3 :(得分:0)

您可以将DynamicParameters类用于通用字段。

Dictionary<string, object> Filters = new Dictionary<string, object>();
Filters.Add("UserName", "admin");
Filters.Add("Email", "admin@admin.com");
var builder = new SqlBuilder();
var select = builder.AddTemplate("select * from SomeTable /**where**/");
var parameter = new DynamicParameters();
foreach (var filter in Filters)
{
    parameter.Add(filter.Key, filter.Value);
    builder.Where($"{filter.Key} = @{filter.Key}");                        
}


var searchResult = appCon.Query<ApplicationUser>(select.RawSql, parameter);