0. 前言

之前四篇介绍了一个国内开发者开发的优秀框架SqlSugar,给我们眼前一亮的感觉。这一篇,我们将试试另一个出镜率比较高的ORM框架-Dapper。

Dapper是一个轻量级的ORM框架,其以高速、简单易用为特点。在某些时候,效率甚至可以与ADO.NET 媲美。那么,吹得天花乱坠,就让我们实际看看它的表现吧。

1. 开始使用

照例,先创建一个项目:DapperDemo

dotnet new console --name DapperDemo

然后切换到目录里:

cd DapperDemo

添加包支持:

dotnet add package Dapper

如果不出意外的话,目前项目中已经安装好了Dapper。现在就让我们开始愉快的使用吧。

首先,需要注意的一点是,与其他的ORM框架不同的是,Dapper需要我们手动创建一个IConnection。Dapper的所有操作都是依托于IConnection来操作,而且Dapper将其支持的方法封装成了IConnection的扩展方法。

所以,在使用之前我们需要先创建一个IConnection。为了方便演示,我把之前SqlSugar演示用过的测试数据库拿过来了,是一个SQLite,所以我们需要先安装一个SQLite的驱动:

dotnet add package Microsoft.Data.SQLite

在Program.cs中引入两个包:

using Microsoft.Data.Sqlite;
using Dapper;

在Main方法里创建一个IConnection:

using(var connection = new SqliteConnection("Data Source=./demo.db"))
{

}

2. 多数据查询

Dapper的查询相当简单:

var result = connection.Query("select * from Persion");

传入一个SQL语句,返回一个可枚举对象。如果不指定类型,将返回类型为dynamic的列表。我们来看一下Query方法的相关声明:

public static IEnumerable<dynamic> Query(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null);

public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null);

public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string sql, Type[] types, Func<object[], TReturn> map, object param = null, IDbTransaction transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null);

我们就以最常用的三个为例,给大伙分析一下参数以及调用方式:

  • cnn 一个数据库连接,所以Dapper不负责管理数据库连接,这部分由我们手动管理

  • sql 传入的SQL语句,Dapper以IDbConnection为基础,以SQL为执行命令,所以必须我们来传入SQL语句

  • param 一个可以为Null的Object类型,表示SQL的参数化,Dapper对参数化做了一些优化,在SQL的参数化里,参数名映射到了object的属性上。

  • transaction 表示是否有IConnection级别的事务,默认为null,传入后该指令会被事务包含

  • buffered 缓存

  • commandTimeout 命令执行是否超时以及超时时间

  • commandType 表示命令模式 有 Text 普通模式,StoredProcedure 存储过程 ,TableDirect 表查询

  • splitOn 默认情况下以Id 作为两个对象之间的区分

3. 单数据查询

Dapper在数据查询方面不仅支持集合作为查询结果,还可以获取单个数据。

一共有四种方式获取单数据:

public static T QueryFirst<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);
public static T QueryFirstOrDefault<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);

QueryFirst 表示获取第一条查询结果,如果没有结果,则会抛出一个异常。

QueryFirstOrDefault 与QueryFirst一样,但不同的是,如果没有则不会抛出异常,而是直接返回一个该类型的默认值,数值类型的默认值为(0),引用类型的默认值为Null。

public static T QuerySingle<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);
public static T QuerySingleOrDefault<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);

QuerySingle也能查询单条数据作为结果,但与QueryFirst不同的是QuerySingle查询时,如果数据存在多行将会抛出异常,如果不想要异常则可以使用QuerySingleOrDefault作为查询方法。

4. QueryMultiple

这个另外一种查询方式,对于SQL语句来说,没有明显的限制,所以我们有时候可以传入多个查询SQL语句进去,然后分别获取来自各个表的查询数据:

string sql = "SELECT * FROM Invoice WHERE InvoiceID = @InvoiceID; SELECT * FROM InvoiceItem WHERE InvoiceID = @InvoiceID;";

using (var connection = My.ConnectionFactory())
{
   connection.Open();

   using (var multi = connection.QueryMultiple(sql, new {InvoiceID = 1}))
   {
       var invoice = multi.Read<Invoice>().First();
       var invoiceItems = multi.Read<InvoiceItem>().ToList();
   }
}

看一下它的基本参数和方法声明:

public static GridReader QueryMultiple(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);

这个方法返回一个GridReader,通过Read方法获取需要的数据。

5. 不只是查询

Dapper当然不只有查询这一项功能,Dapper支持使用存储过程、insert、update、delete等其他的SQL语句进行操作数据库。使用方式:

string sql = "Invoice_Insert";

using (var connection = My.ConnectionFactory())
{
   var affectedRows = connection.Execute(sql,
       new {Kind = InvoiceKind.WebInvoice, Code = "Single_Insert_1"},
       commandType: CommandType.StoredProcedure);
   var affectedRows2 = connection.Execute(sql,
       new[]
       {
           new {Kind = InvoiceKind.WebInvoice, Code = "Many_Insert_1"},
           new {Kind = InvoiceKind.WebInvoice, Code = "Many_Insert_2"},
           new {Kind = InvoiceKind.StoreInvoice, Code = "Many_Insert_3"}
       },
       commandType: CommandType.StoredProcedure
   );
}

示例就是使用存储过程的例子。

string sql = "INSERT INTO Customers (CustomerName) Values (@CustomerName);";

using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
   var affectedRows = connection.Execute(sql, new {CustomerName = "Mark"});

   Console.WriteLine(affectedRows);

   var customer = connection.Query<Customer>("Select * FROM CUSTOMERS WHERE CustomerName = 'Mark'").ToList();

   FiddleHelper.WriteTable(customer);
}
//== 多次插入
string sql = "INSERT INTO Customers (CustomerName) Values (@CustomerName);";

using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
   connection.Open();

   var affectedRows = connection.Execute(sql,
   new[]
   {
   new {CustomerName = "John"},
   new {CustomerName = "Andy"},
   new {CustomerName = "Allan"}
   }
);

这是执行插入的示例。

string sql = "UPDATE Categories SET Description = @Description WHERE CategoryID = @CategoryID;";

using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
   var affectedRows = connection.Execute(sql,new {CategoryID = 1, Description = "Soft drinks, coffees, teas, beers, mixed drinks, and ales"});

   Console.WriteLine(affectedRows);
}

更新。

string sql = "DELETE FROM Customers WHERE CustomerID = @CustomerID";

using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
   var affectedRows = connection.Execute(sql, new {CustomerID = 1});

   Console.WriteLine(affectedRows);
}

删除。

Execute没什么好说的,基本就是执行SQL语句的形式完成增删改成等操作。

值得注意的是:

public static IDataReader ExecuteReader(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);

返回一个IDataReader实例,这个实例可以给DataTable填充数据,使用方法如下:

DataTable table = new DataTable();
table.Load(reader);

以及:

public static T ExecuteScalar<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);

这个方法是返回查询结果的第一行第一列的元素。

6. 总结

如果单说Dapper的话,并没有太多好说的。不过Dapper是真的快,在实际开发中有时候会用Dapper作为EF Core的一个补充。

当然了,Dapper还有很多其他的插件,使用那些插件可以为Dappe带来非一般的提升。我们下一篇将介绍一下Dapper的插件。




©著作权归作者所有:来自51CTO博客作者mb5fdb0f93c5ca2的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. C# 数据操作系列 - 16 SqlSugar 完结篇
  2. C# 数据操作系列 - 13 SqlSugar 初探
  3. C# 数据操作系列 - 9. EF Core 完结篇
  4. php学习小结(类成员重载、全局成员、空间声明及成员访问)
  5. 第8章 0203-静态绑定,接口与抽象类,学习心得、笔记(抽象类、继承、
  6. 简单写一个失败重试的方法
  7. 谈谈有关模版模式及设计原则
  8. MySQL的EXPLAIN其实很简单
  9. CURD常用操作、select常用查询、预处理原理

随机推荐

  1. Android studio怎样隐藏标题栏
  2. Android 2.3的camera的虚拟对焦的去除
  3. 【Android基础】Android开发学习笔记
  4. 永久改变android 模拟器分区大小
  5. 【Android】配置文件属性说明
  6. Android声音播放实例代码
  7. Android中attr自定义标签详解
  8. Android练手小项目(KTReader)基于mvp架构(三
  9. 使用Android(安卓)Studio为系统级的app签
  10. android 设置布局为无标题样式