Dapper使用技巧分享

Dapper是轻量级的.net ORM框架,配合linq和泛型,让C#操作数据的代码简洁、高效又灵活!最近的工作项目中使用了Dapper,在这里分享一些实用技巧。阅读之前需要了解一些基本的使用方法,参见官网http://dapper-tutorial.net/ 。

  • 写可撤销的查询:

你的应用程序应该给用户提供各种“取消”的功能,这就在包括了查询数据的时候撤销一条正在执行的查询,Dapper像很多ORM一样提供了这个操作,看看这段代码:

// using Dapper;

var products = sqlConnection.QueryAsync<Product>(new CommandDefinition(
                    queryProducts,
                    new { Type = "SomeType" },
                    commandTimeout: 60,
                    cancellationToken: myToken)).Result.ToList();

这里Product是定义好的数据类,queryProducts是查询文本,myToken是定义好的Task的CancellationToken。这段代码使用QueryAsync异步方法实现了可撤销的查询操作,开发者需要把控制撤销的myToken传给CommandDefinition的可选参数cancellationToken。使用代码之前,要了解一下C#的Task概念。

另外值得注意的是,查询的TimeOut可以通过commandTimeout设置(默认30s)。

  • 使用事务:

事务是数据库的重要概念,Dapper对事务提供了很好的支持,看看这段代码:

1 // using System.Linq;
2 // using System.Data.SqlClient;
3 using (SqlTransaction tran = sqlConn.BeginTransaction())
4 {
5     var pars = ProductsWithNewPrice.Select(t => { return new { t.ProductID, t.Price }; });
6     sqlConn.Execute(UpdateProductPrice, pars, transaction: tran);
7     tran.Commit();
8 }

通过喜闻乐见的using形式执行一段事务,这里假设ProductsWithNewPrice是一个具有新价格的Product类的集合,事务的目的是把这些新价格通过Update语句更新到数据库中。第5行用linq取出了具有ProductID和Price字段的临时类型的集合,这个集合作为下面一行所执行的sql语句们的参数。UpdateProductPrice是查询文本,应该是类似这样的“UPDATE dbo.Product set Price = @Price WHERE ProductID = @ProductID;”。因为使用了transaction,pars集合中的所有参数对应的"UPDATE"语句会在同一个事务中完成。

  • 从数据库取UTC时间:

我们假设工作环境中数据库一直使用UTC时间(现实经常是这样),我们写的代码经常从数据库中读取时间并转化成C#的DateTime结构。转化的时候Datretime.Kind属性经常被忽略,这可能导致随后的使用中把时间值当做本地时间。要确保避免这样的错误,我们可以做一个设定,把Dapper取到的值指定DateTimeKind为UTC,并把正确的UTC时间存储到数据库。代码是这样的,先创建DateTimeHandler类:

    public class DateTimeHandler : SqlMapper.TypeHandler<DateTime>
    {
        public override void SetValue(IDbDataParameter parameter, DateTime value)
        {
            parameter.Value = DateTime.SpecifyKind(value, DateTimeKind.Utc);
        }

        public override DateTime Parse(object value)
        {
            return DateTime.SpecifyKind(Convert.ToDateTime(value), DateTimeKind.Utc);
        }
    }

然后在你的类的构造函数中加入这行:

            SqlMapper.AddTypeHandler(new DateTimeHandler());

这样,Dapper取到的时间值和通过Dapper保存到数据库的时间值就都是UTC时间了。

  • 使用字符串变量名拼接多个SQL语句

请看下面这段代码。这里使用加号“+”拼接了两个不同功能的SQL语句,并且让两个语句都可以复用!我认为这在指定情景中是一个很好的实践。

    var nextWorkID = sqlConn.Query<int>(SubmitCurrentWork + FindNextWorkID, new { currentWorkID, currentWorkResult }).FirstOrDefault();

不过这样使用Dapper有两个要求:

  1. 每个SQL字符串变量都要以分号结尾。
  2. 不同SQL语句中的变量名必须是一样的。

满足了这两个要求才能写上面那样的代码。上面代码中的SQL字符串变量可以是下面这样:

    string SubmitCurrentWork = "UPDATE dbo.Works SET WorkResult = @currentWorkResult, Status = 'Done' WHERE ID = @currentWorkID;";
    string FindNextWorkID = "SELECT TOP 1 ID FROM dbo.Works WHERE Status != 'Done';"; // 如果这里有名为@currentWorkResult或@currentWorkID的变量,其用途/含义要和上面的语句一致

 以上就是自己的一点经验总结,欢迎拍砖!

posted on 2019-03-19 21:21 因纽特猎人 阅读(...) 评论(...) 编辑 收藏

公告

导航

统计

  • 随笔 - 2
  • 文章 - 0
  • 评论 - 1
  • 引用 - 0