如何在模型中传递时使用Dapper构建动态Where子句

Eld*_*ian 25 .net c# sql dapper

我有一个示例模型,如下所示:

public class PersonModel
{
     public int Id {get; set;}
     public string FirstName {get; set;}
     public string Lastname {get; set;}
     public string City {get; set;}
}
Run Code Online (Sandbox Code Playgroud)

在我的存储库中,我想创建一个我传入模型的搜索方法 - 但并不是所有字段都会被填充.我想创建一个WHERE和AND,基于是否填充了模型中的字段.如果没有填充该字段,那么我不想为它创建WHERE子句.

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

SELECT * FROM PersonTable WHERE FirstName = @firstName AND City = @city
Run Code Online (Sandbox Code Playgroud)

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

SELECT * FROM PersonTable WHERE City = @city
Run Code Online (Sandbox Code Playgroud)

我的回购方法看起来像这样

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();
}
Run Code Online (Sandbox Code Playgroud)

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

Voi*_*Ray 53

您也可以使用Dapper的SqlBuilder

这是一个例子:

    [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);
    }
Run Code Online (Sandbox Code Playgroud)

你可以在这里找到一些例子!


JFM*_*JFM 17

这应该为你做的,干净简单:

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();
Run Code Online (Sandbox Code Playgroud)

  • 这比使用C#条件语句构建SQL更干净。考虑使用OPTION(RECOMPILE),以便查询优化可以考虑所提供的实际参数。 (3认同)

dri*_*zin 8

DapperQueryBuilder是 Dapper.SqlBuilder 的替代品,但更容易使用:

var query = cn.QueryBuilder($"SELECT * FROM PersonTable WHERE 1=1");

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

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

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

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


var results = query.Query<Person>(); 
Run Code Online (Sandbox Code Playgroud)

Query<Person>()将调用 Dapper 传递底层 SQL 和参数 - 并且底层查询是完全参数化的 SQLWHERE FirstName = @p0 AND LastName = @p1等)。参数是从字符串插值中自动捕获的(但它可以安全地防止 SQL 注入)。

--

替代语法
与 Dapper.SqlBuilder 类似,您也可以使用以下/**where**/语法(它将自动加入条件,无需手动使用AND1==1欺骗):

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>(); 
Run Code Online (Sandbox Code Playgroud)

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