Dapper异步使用学习
Dapper已经赢得了C#轻量级ORM的王者称号,但却被很多人认为是一款用于.Net环境的简单的对象映射器。当人们希望自己编写具有最佳性能的SQL查询时,他们会更喜欢Dapper。Dapper是100%安全的!你可以像往常一样使用参数化查询,不用担心被SQL注入的问题,此外Dapper还支持事务操作,第三方扩展的Dapper. Plus 还支持批量操作!而且已经支持异步了,最近我就尝试了使用Dapper的异步方法来操作数据库,所以在此做个分享,也加深一遍理解。
尤其是对三表Join操作的splitOn参数的理解,以及事务操作的使用,说实话,文档里有很多细节并未详细说明,只能靠你自己去实践,模拟业务场景去实验是最佳的学习方式,很多技术内部细节都能靠尝试和实验反推出来。
Dapper官方主页:https://dapper-tutorial.net/
本次涉及的几个命名空间: MySql.Data.MySqlClient,Dapper,Newtonsoft.Json,System.Transactions;
1. 数据库创建表
学习Dapper首先要先准备好一个数据库,这里我选择MySQL,Mysql比较常用,基本上生产环境普遍都是Mysql,我也曾尝试安装过Sql Server 2017 但是实在是太大了,作为开发者,它远不如Mysql更轻量,更易安装使用。先建一个数据库,创建三张表,角色表,用户表,部门表,三张表有关联关系,SQL语句如下:
-- 部门表
CREATE TABLE `Departments` (
`ID` int(0) NOT NULL AUTO_INCREMENT,
`DepartmentName` varchar(50)
`PDepartmentID` int(0) NOT NULL,
PRIMARY KEY (`ID`) USING BTREE
)
-- 角色表
CREATE TABLE `Roles` (
`ID` int(0) NOT NULL AUTO_INCREMENT,
`RoleName` varchar(20)
PRIMARY KEY (`ID`) USING BTREE
)
-- 用户表
CREATE TABLE `Users` (
`ID` int(0) NOT NULL AUTO_INCREMENT,
`DepartmentID` int(0) DEFAULT NULL,
`Name` varchar(50)
`Password` varchar(50)
`RoleID` int(0) DEFAULT NULL,
`UserName` varchar(50)
PRIMARY KEY (`ID`) USING BTREE
)
2. 实体类创建
使用过ORM框架的童鞋们都知道,如果使用ORM,必要条件就是要创建与表各字段关系对应的实体类,Object-Relationl Mapping,它的作用就是在关系型数据库和对象之间作一个映射。
/// <summary>
/// 角色
/// </summary>
public class Roles
{
public int ID { get; set; }
public string RoleName { get; set; }
}
/// <summary>
/// 部门
/// </summary>
public class Departments
{
public int ID { get; set; }
public string DepartmentName { get; set; }
public int PDepartmentID { get; set; }
}
/// <summary>
/// 用户
/// </summary>
public class Users
{
public int ID { get; set; }
public int DepartmentID { get; set; }
public string Name { get; set; }
public string Password { get; set; }
public int RoleID { get; set; }
public string UserName { get; set; }
}
/// <summary>
/// 用户角色综合
/// </summary>
public class UsersAndRole
{
public int ID { get; set; }
public string Name { get; set; }
public string Password { get; set; }
public string UserName { get; set; }
public string RoleName { get; set; }
public string DepartmentName { get; set; }
public Roles Role { get; set; }
}
3. 执行插入/修改/删除
插入,删除和修改操作,基本相同,所以这里只写了插入操作的实例代码。
// 插入单个对象
public static async Task<int> InsertRoleAsync()
{
using (IDbConnection connection = new MySqlConnection(connectionString))
{
return await connection.ExecuteAsync("insert into Roles(RoleName) values(@RoleName)",
new Roles()
{
RoleName = "管理员"
});
}
}
// 插入多个对象
public static async Task<int> InsertBatchRoleAsync()
{
using (IDbConnection connection = new MySqlConnection(connectionString))
{
return await connection.ExecuteAsync("insert into Roles(RoleName) values(@RoleName)",
new List<Roles>()
{
new Roles(){ RoleName="a"},
new Roles(){ RoleName="b"},
new Roles(){ RoleName="c"},
});
}
}
4. 基本查询操作
基本查询语句操作包括,无参数查询,有参数查询,In语句查询,及 多语句执行查询,这里均采用异步的方法。
/// <summary>
/// 无参查询所有数据
/// </summary>
/// <returns></returns>
public static List<Roles> QueryRoles()
{
using (IDbConnection connection = new MySqlConnection(connectionString))
{
return connection.QueryAsync<Roles>("select * from Roles").Result.ToList();
}
}
/// <summary>
/// 查询指定数据
/// </summary>
/// <param name="person"></param>
/// <returns></returns>
public static Roles QueryRolesByRoleName(string roleName)
{
using (IDbConnection connection = new MySqlConnection(connectionString))
{
return connection.QueryAsync<Roles>("select * from Roles where RoleName=@RoleName",
new { RoleName= roleName }).Result.SingleOrDefault();
}
}
/// <summary>
/// In语句操作
/// </summary>
public static List<Roles> QueryIn()
{
using (IDbConnection connection = new MySqlConnection(connectionString))
{
var sql = "select * from Roles where id in @ids";
return connection.QueryAsync<Roles>(sql, new { ids = new int[2] { 1, 2 }, }).Result.ToList();
}
}
/// <summary>
/// 多语句操作
/// </summary>
public static void QueryUsersAndRolesMultiple()
{
using (IDbConnection connection = new MySqlConnection(connectionString))
{
var sql = "select * from Users; select * from Roles";
var multiReader = connection.QueryMultiple(sql);
var roleList = multiReader.Read<Roles>();
var userList = multiReader.Read<Users>();
Console.WriteLine(JsonConvert.SerializeObject(roleList));
Console.WriteLine(JsonConvert.SerializeObject(userList));
multiReader.Dispose();
}
}
5. Join内联接查询
Join内联接查询,这个实例是我特意设计出来的,采用三个关联表Join联合查询出用户的详细数据,根据字段的顺序,我将splitOn分割参数设置为"Name"字段,因为只要在Name字段时才能查出所有字段的值,Dapper扫描字段是按照从右向左的顺序扫的,所以尽量选择字段顺序最开始的除了ID之外的字段作为分割参数。
记住SQL语句中字段的顺序:u.id as ID,Name,Password,UserName,RoleName,DepartmentName
/// <summary>
/// Join查询
/// </summary>
/// <param name="UserName"></param>
/// <returns></returns>
public static UsersAndRole QueryAsyncJoin(string UserName)
{
using (IDbConnection connection = new MySqlConnection(connectionString))
{
var sql = @"SELECT u.id as ID,Name,Password,UserName,RoleName,DepartmentName
FROM Users u
Join Roles r on u.RoleID=r.ID
Join Departments d on u.DepartmentID=d.ID
WHERE u.UserName=@userName
";
var result = connection.QueryAsync<Roles, UsersAndRole, UsersAndRole>(sql,
(role,urd) =>
{
urd.Role = role;
return urd;
},new { userName = UserName },
splitOn: "Name");
return (UsersAndRole)result.Result.FirstOrDefault();
}
}
执行方法
var result = QueryAsyncJoin("大林");
Console.WriteLine(JsonConvert.SerializeObject(result));
详细讲解一下,为了方便展示,我将查询结果Json序列化了,方便观察,我们先看按Name字段分割时的运行结果截图,可以看到所有字段值都查询出来了
如果按Password字段分割呢?你看显然,Name值就空了
再看按UserName分割,然后发现Name,Password都空了,你看,规律就找到了吧。
6. 事务操作
事务操作分为Dapper的内部事务方法,和.Net 基础库自带的事务方法。
/// <summary>
/// Dapper事务
/// </summary>
/// <returns></returns>
public static int TransactionDapper()
{
int effaffectedRows = -1;
using (IDbConnection connection = new MySqlConnection(connectionString))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
effaffectedRows = connection.Execute("insert into Roles(RoleName) values(@RoleName)",
new Roles()
{
RoleName = "管理员"
}, transaction: transaction);
transaction.Commit();
}
}
return effaffectedRows;
}
/// <summary>
/// 系统事务
/// </summary>
/// <returns></returns>
public static int TransactionSystem()
{
int effaffectedRows = -1;
using (var transaction = new TransactionScope())
{
using (IDbConnection connection = new MySqlConnection(connectionString))
{
connection.Open();
effaffectedRows = connection.Execute("insert into Roles(RoleName) values(@RoleName)",
new Roles()
{
RoleName = "管理员"
});
}
transaction.Complete();
return effaffectedRows;
}
}
7. Dapper 官方文档链接
https://dapper-tutorial.net/dapper
转载:https://blog.csdn.net/DahlinSky/article/details/104766612