【问题标题】:How do I build a dynamic Where clause with Dapper when passing in a model传入模型时如何使用 Dapper 构建动态 Where 子句
【发布时间】:2017-02-08 09:22:49
【问题描述】:

我有一个看起来像这样的示例模型:

public class PersonModel
{
     public int Id {get; set;}
     public string FirstName {get; set;}
     public string Lastname {get; set;}
     public string City {get; set;}
}

在我的存储库中,我想创建一个搜索方法,在其中传递我的模型 - 但并非所有字段都将始终被填充。我想根据模型中的字段是否已填充来创建 WHERE 和 AND。如果该字段未填充,那么我不想为其创建 WHERE 子句。

例如 - 如果我传入 FirstName = "Bob" 和 City = "Boston",那么我希望我的搜索看起来像这样:

SELECT * FROM PersonTable WHERE FirstName = @firstName AND City = @city

由于我没有传入 Id 或 LastName,我不希望将它们添加到查询中。如果我只是传入 City = "Boston" 那么我希望它看起来像这样:

SELECT * FROM PersonTable WHERE City = @city

我的 repo 方法看起来像这样

using Dapper;
public List<PersonModel> Search(PersonModel model)
{
//db = DbConnection connection
    var selectSql = "SELECT * FROM PersonTable "; //build out where clause somehow
    return db.Query<PersonModel>(selectSql).ToList();
}

我的问题是如何在我的 repo 方法中正确构建它?

【问题讨论】:

  • 您可以有条件地附加 where 子句。仪式?
  • 我假设是的,是的。但是,我正在寻找一个很好的例子来说明如何做到这一点。

标签: c# sql .net dapper


【解决方案1】:

你也可以使用 Dapper 的SqlBuilder

请注意,您必须安装 Dapper.SqlBuilder NuGet 包,因为 Dapper 的主要发行版不附带它。

这是一个例子:

    [Test]
    public void Test()
    {
        var model = new PersonModel {FirstName = "Bar", City = "New York"};

        var builder = new SqlBuilder();

        //note the 'where' in-line comment is required, it is a replacement token
        var selector = builder.AddTemplate("select * from table /**where**/");

        if (model.Id > 0)
            builder.Where("Id = @Id", new { model.Id });

        if (!string.IsNullOrEmpty(model.FirstName))
            builder.Where("FirstName = @FirstName", new { model.FirstName });

        if (!string.IsNullOrEmpty(model.Lastname))
            builder.Where("Lastname = @Lastname", new { model.Lastname });

        if (!string.IsNullOrEmpty(model.City))
            builder.Where("City = @City", new { model.City });

        Assert.That(selector.RawSql, Is.EqualTo("select * from table WHERE FirstName = @FirstName AND City = @City\n"));

        //var rows = sqlConnection.Query(selector.RawSql, selector.Parameters);
    }

你可以找到一些例子here

【讨论】:

  • 也适用于List&lt;int&gt;List&lt;string&gt; 参数 ?
  • SqlBuilder 对于这句话:SELECT * FROM TABLE1 WHERE id IN (SELECT t2.id FROM TABLE2 as t2 , TABLE1 as t1 WHERE t1.id=t2.id AND /**where**/ ) ?
  • @tCode,只需将 'select *' 更改为 'update' 并将 .Query() 更改为 .Execute()
【解决方案2】:

这应该可以为您解决问题,简洁明了:

var selectSql = "SELECT * FROM PersonTable WHERE (@FirstName IS NULL OR FirstName =  @FirstName) AND (@LastName IS NULL OR LastName =  @LastName) AND (@City IS NULL OR City =  @City) AND (@Id IS NULL OR Id =  @Id) OPTION(RECOMPILE)";

return conn.Query<PersonModel>(selectSql, new
{
     model.FirstName,
     model.Lastname,
     model.City,
     Id = model.Id == 0? (int?)null: (int?)model.Id        
}).ToList();

【讨论】:

  • 这比使用 C# 条件构建 SQL 更简洁。考虑使用 OPTION(RECOMPILE),以便查询优化可以考虑提供的实际参数。
  • 如果我没有选择使用 Dapper.SqlBuilder,我会选择这个作为接受的答案。
  • 对于List&lt;int&gt;List&lt;string&gt; 参数 ?
  • 重申 bbsimonbbs 的观点,如果您不添加 OPTION (RECOMPILE),您的查询在某些情况下可能会非常慢。 SQL 会针对一个执行路径进行优化,只有该路径才能合理运行。
  • 关于 OPTION(RECOMPILE) 声明,非常感谢 bbsimonbb 和 Marie 的陈述,我现在已将其添加到帖子中
【解决方案3】:

如果您想尝试其他替代方案,DapperQueryBuilder 可能更易于使用:

var query = cn.QueryBuilder($@"
    SELECT * 
    FROM PersonTable
   /**where**/
");

if (model.Id > 0)
    query.Where($"Id = {model.Id}");

if (!string.IsNullOrEmpty(model.FirstName))
    query.Where($"FirstName = {model.FirstName}");

if (!string.IsNullOrEmpty(model.Lastname))
    query.Where($"Lastname = {model.Lastname}");

if (!string.IsNullOrEmpty(model.City))
    query.Where($"City = {model.City}");


var results = query.Query<Person>(); 

Query&lt;Person&gt;() 将调用 Dapper 传递底层 SQL 和参数。

底层查询是完全参数化的 SQL
WHERE FirstName = @p0 AND LastName = @p1

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

【讨论】:

    【解决方案4】:
    bool isFirstWhereSet = false;
    bool isCityWhereSet = false;
    string sqlQuery = "SELECT * FROM PersonTable "  ;
    if (! String.IsNullOrEmpty(model.FirstName ))
    {
    sqlQuery  =sqlQuery  + "WHERE FirstName =@FirstName" ;
    isFirstWhereSet = true;
    }
    
    if (! String.IsNullOrEmpty(model.City))
    {
    isCityWhereSet  = true ;
    if (! isFirstWhereSet )
    sqlQuery  = sqlQuery  + " WHERE City = @city";
    else
    sqlQuery  = sqlQuery  + " AND City = @city";
    }
    
    
    
    if (isFirstWhereSet == true && isCityWhereSet == true )
     return db.Query<PersonModel>(sqlQuery , new { FirstName = model.FirstName  , City = mode.City}).ToList();
    else if (isFirstWhereSet == true && isCityWhereSet  == false)
     return db.Query<PersonModel>(sqlQuery , new { FirstName = model.FirstName }).ToList();
    else if (isFirstWhereSet == false && isCityWhereSet  == true)
     return db.Query<PersonModel>(sqlQuery , new { City= model.City}).ToList();
    else
    {
     return db.Query<PersonModel>(sqlQuery).ToList();
    }
    

    【讨论】:

      【解决方案5】:

      您可以使用ExpressionExtensionSQL 库。该库将 lambda 表达式转换为 where 子句,并且可以与 dapper 和 ADO 一起使用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-10-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-12
        • 2019-06-25
        相关资源
        最近更新 更多