是否有更清洁的Dapper方法只更新使用Dapper更改的列?

时间:2018-03-15 15:29:22

标签: dapper

我正在寻找一种只在Dapper中更新设置属性的方法。即只有在非空属性时才更新实体的属性。

我用如下所示的相当粗略的方法解决了同样的问题,但我相信应该采用更简洁的方式来做到这一点。

 public void UpdateCustomer(Customer cust)
    {
        try
        {
            StringBuilder sb = new StringBuilder("UPDATE CUSTOMER_SETUP  SET DATE_MODIFIED = @DATE_MODIFIED ");
           if(cust.BUSINESSNAME != null) sb.Append(",BUSINESSNAME = @BUSINESSNAME ");
            if (cust.BUSINESS_ADDRESS != null) sb.Append(",BUSINESS_ADDRESS = @BUSINESS_ADDRESS ");
            if (cust.CONTACT_NAME != null) sb.Append(",CONTACT_NAME = @CONTACT_NAME ");
            if (cust.CONTACT_TITLE != null) sb.Append(",CONTACT_TITLE = @CONTACT_TITLE ");
            if (cust.CONTACT_PHONE1 != null) sb.Append(",CONTACT_PHONE1 = @CONTACT_PHONE1 ");
            if (cust.CONTACT_PHONE2 != null) sb.Append(",CONTACT_PHONE2 = @CONTACT_PHONE2 ");
            if (cust.CONTACT_EMAIL != null) sb.Append(",CONTACT_EMAIL = @CONTACT_EMAIL ");
            if (cust.CONTACT_URL != null) sb.Append(",CONTACT_URL = @CONTACT_URL ");
            if (cust.DATE_CREATED != null) sb.Append(",DATE_CREATED = @DATE_CREATED ");
            if (cust.CUSTOMER_TYPE != null) sb.Append(",CUSTOMER_TYPE = @CUSTOMER_TYPE ");
            if (cust.SUBSCRIPTION_TYPE != null) sb.Append(",SUBSCRIPTION_TYPE = @SUBSCRIPTION_TYPE ");


            sb.Append("WHERE ID = @ID ");
            sb.Append("; SELECT CAST(SCOPE_IDENTITY() as int ");

            var sql = sb.ToString();


            using (connection = new SqlConnection(connectString))
            {
                connection.Execute(sql, cust);

            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

4 个答案:

答案 0 :(得分:2)

您正在寻找的功能称为更改跟踪。此功能是更大的工作单元模式的一部分。

Dapper不支持更改跟踪。

Dapper的附加组件很少有人在不同的级别上支持这一点。有关比较图表,请参阅this博文。如图表所示,Dapper.Contrib和Dapper.Rainbow以不同的方式支持它。

编辑:回答您的评论

正如@MarcGravell在评论中所说,POCO属性的null值很常见。它并不总是意味着“不要更新那个领域”。这也可能意味着“将该数据库字段设置为null(或DBNull)”。由于属性值null没有任何保证意义,因此大多数ORM以与Dapper相同的方式实现它。

答案 1 :(得分:0)

我们将Dapper.Rainbow的Snapshotter包装成改变跟踪器。您需要一个db对象的实例才能工作。

它非常适合我们提供您可以很容易地用来生成您所追求的SQL的字典。

它可能看起来像这样:

public class Foo{public string Name{get;set;}}

var foo = new Foo();

    var snapshotter = Snapshotter.Start(foo);

    foo.Name = "A new name";

    var dynparams = snapshotter.Diff(); //we basically wrap the snapshotter to give a dict here, but it's basically the same thing

    foreach(var name in dynparams.ParameterNames){
    sb.Append($",{name} = @{dynparams[name]} ");
    }

答案 2 :(得分:0)

自己动手。

为模型添加私有集合,读取时复制数据。更新时比较新旧。根据需要构建 SQL 语句。

通过增加数据库前处理,而不是让列“干火”给数据库供应商,是否会带来净性能提升?我认为大多数数据库供应商都知道列数据何时不变,并且会在必要时排除这些列,例如特定列上的更新触发器。

答案 3 :(得分:0)

这是使用您想要的 Dapper 的更新查询示例。或许能帮到你。

public async Task<bool> UpdateDataByIdAsync(Data data)
    {          
        using MySqlConnection connection = new MySqlConnection("your connection string");
        const string sqlQuery = @"Update Datas Set name = @name, description = @description, tags = @tags
                where data_id = @data_id;";

        var rowAffected = await connection.ExecuteAsync(sqlQuery, data);
        return rowAffected > 0;
    }