简介:
dapper 只是一个代码文件,完全开源,你可以在项目里任何位置,来实现数据到对象ORM操作(当然先引用Dapper文件),体积小速度快。使用好处增删改查比较快,不用自己写sql,因为这都是重复技术含量低的工作,还有程序中大量的数据库中读取数据然后创建model,并且为model字段赋值,这都是很轻松的,个人认为Dapper可以看做HelpSQL,甚至比HelperSQL性能高一点。如果你喜欢原生的SQL,那么有喜欢ORM的简单,那你一定钟情于Dapper 并且爱上他。Dapper的优势:
- Dapper是一个轻量级ORM类,代码就是一个SQLMapper.cs文件,编译后一般在40k左右的dll;
- Dapper快,为啥说快呢?因为Dapepr速度接近IDataReader,取列表的数据超过DataTable;
- Dapper支持什么数据库?支持Mysql,sqlLite,SQLServer,Oracle等一系列数据库,(备注:我个人在在做demo中,就是使用了Mysql,SQLServer,公司和个电脑装的数据库不一样,就都测试了);
- Dapper的R支持多表并联的对象,支持一对多,多对多关系,并且没侵入性,想用就用 ;
- Dapper原理就是通过Emit反射IDateReader的队列,来快速得到和产生对象;这也是性能高的原因之一;
Dapper语法简单,快速入手。如果面试,让你说出Dapper的好处,为啥用Dapper,上面回答出来,杠杠的。。。。。。。。面试官:我靠,小伙子懂的挺多………
Dapper使用
1. 在NuGet中引用Dapper


2. 新建一个ConnectionFactory类
创建链接对象,這里我们封装两个方法分别获取SQLServerr 和MySQL
public class ConnectionFactory{//获取web 中的配置文件private static readonly string QlwMysqlConnection = ConfigurationManager.AppSettings["sqlconnectionString"];/// <summary>/// sqlServer 数据库/// </summary>/// <returns></returns>public static IDbConnection SqlServerConnection(){string sqlconnectionString = QlwMysqlConnection; //ConfigurationManager.ConnectionStrings["sqlconnectionString"].ToString();var connection = new SqlConnection(sqlconnectionString);if (connection.State == ConnectionState.Closed){connection.Open();}return connection;}/// <summary>/// mySQl 数据库/// </summary>/// <returns></returns>public static IDbConnection MySqlConnection(){string mysqlconnectionString = QlwMysqlConnection; //ConfigurationManager.ConnectionStrings["mysqlconnectionString"].ToString();var connection = new MySqlConnection(mysqlconnectionString);if (connection.State == ConnectionState.Closed){connection.Open();}return connection;}}
3. Dapper封装方法
(1)先看一下后台:SqlMapper,封装了给我们提供了那些方法:

public static class DapperDBContext{public static List<T> AsList<T>(this IEnumerable<T> source){if (source != null && !(source is List<T>))return source.ToList();return (List<T>)source;}//参数我们跟后台封装方法保持一致public static int Execute(string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, int databaseOption = 1){using (var conn = ConnectionFactory.MySqlConnection()){var info = "SQL语句:" + sql + " \n SQL参数: " + JsonConvert.SerializeObject(param) + " \n";// LogHelper.ErrorLog(info); // 可以记录操作var sw = new Stopwatch(); sw.Start();var restult = conn.Execute(sql, param, transaction, commandTimeout, commandType);sw.Stop();LogHelper.ErrorLog(info + "耗时:" + sw.ElapsedMilliseconds + (sw.ElapsedMilliseconds > 1000 ? "#####" : string.Empty) + "\n"); // 可以记录操作return restult;}}public static int Execute(CommandDefinition command, int databaseOption = 1){using (var conn = ConnectionFactory.MySqlConnection()){var info = " SQL语句:" + command.CommandText + " \n SQL命令类型: " + command.CommandType + " \n";// LogHelper.Info(info);// 可以记录操作var sw = new Stopwatch(); sw.Start();var restult = conn.Execute(command);sw.Stop();// LogHelper.Info(info + "耗时:" + sw.ElapsedMilliseconds + (sw.ElapsedMilliseconds > 1000 ? "#####" : string.Empty) + "\n");// 可以记录操作return restult;}}}
4. Dapper常用CRUD
4.1 Select查询
- SQLMapper中QueryMultiple()方法
//// 摘要:// Execute a command that returns multiple result sets, and access each in turn: // 上句话的翻译是: 执行一个返回多个结果集的命令,并依次访问每个结果集public static SqlMapper.GridReader QueryMultiple(this IDbConnection cnn, CommandDefinition command);//// 摘要:// Execute a command that returns multiple result sets, and access each in turnpublic static SqlMapper.GridReader QueryMultiple(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);//// 摘要:// Execute a command that returns multiple result sets, and access each in turnpublic static Task<SqlMapper.GridReader> QueryMultipleAsync(this IDbConnection cnn, CommandDefinition command);//// 摘要:// Execute a command that returns multiple result sets, and access each in turnpublic static Task<SqlMapper.GridReader> QueryMultipleAsync(this IDbConnection cnn, string sql, object param = null,IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);
- 在DapperDBContext 中加个方法,我们可以根据不同业务扩展方法,
/// <summary>/// WueryMultiplie 执行一个返回多个结果集的命令,并依次访问每个结果集/// </summary>/// <param name="sql"></param>/// <param name="param"></param>/// <param name="transaction"></param>/// <param name="commandTimeout"></param>/// <param name="commandType"></param>/// <param name="databaseOption"></param>/// <returns></returns>public static Dapper.SqlMapper.GridReader QueryMultiple(string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, int databaseOption = 1){var conn = ConnectionFactory.MySqlConnection();var sw = new Stopwatch(); sw.Start();try{// 因为using 的作用域之后,连接自动关闭,//这里需要说明的是,在数据读取完毕之后,不再需要SqlDataReader时,必须将其进行手动关闭var restult = conn.QueryMultiple(sql, param, transaction, commandTimeout, commandType);sw.Stop();return restult;}catch (Exception ex){LogHelper.ErrorLog(ex.ToString());throw new Exception(ex.ToString());}}
注意事项:不知道你在上面代码中有没有遇到一个问题,上篇文章我们封装用到using,这次没有用到,是因为封装过程报错:报错:“阅读器关闭时尝试调用 Read 无效” ,原因也很简单:因为using 的作用域之后,连接自动关闭,这里需要说明的是,在数据读取完毕或者不再需要SqlDataReader时,必须将其进行手动关闭。
- SQL调用
/// <summary>/// 单表查数据/// </summary>/// <returns></returns>public List<Department> select(){string sql = @"select *from Department";var list = DapperDBContext.Query<Department>(sql, null).ToList(); //(多个结果集)为了比较就写一起var all = selectAll();var dep = all.Read<Department>().ToList();var auth = all.Read<AuthResources>().ToList();return list;}/// <summary>/// 多个结果集/// </summary>/// <returns></returns>public Dapper.SqlMapper.GridReader selectAll(){var sql = "select * from Department; select * from AuthResources";var multiReader = DapperDBContext.QueryMultiple(sql);return multiReader;}
效果:


4.2 模糊查询
方法1:
db.Query<Remitente>("SELECT *FROM RemitentesWHERE Nombre LIKE @n", new { n = "%" + nombre + "%" }).ToList();
方法2:

4.3 单条数据插入
public class DepartmentRepository{/// <summary>/// 插入单条数据以及多条数据/// </summary>/// <param name="department"></param>/// <returns></returns>public bool Add(List<Department> department, AuthResources authResources){#region 插入单条数据string sql = @" INSERT INTO Department (ID,EID,Name,Remarks,Description,Notice,ParentId,AddTime,IsDel,UpdateTime) VALUES(@ID,@EID,@Name,@Remarks,@Description,@Notice,@ParentId,@AddTime,@IsDel,@UpdateTime); ";var result = DapperDBContext.Execute(sql, department[0]);return result >= 1;#endregion}}
4.4 单表批量数据插入
直接把列表传进去
// department是100条数据 public bool Add(List<Department> department, AuthResources authResources){#region 插入单条数据string sql = @" INSERT INTO Department (ID,EID,Name,Remarks,Description,Notice,ParentId,AddTime,IsDel,UpdateTime) VALUES(@ID,@EID,@Name,@Remarks,@Description,@Notice,@ParentId,@AddTime,@IsDel,@UpdateTime); ";var result = DapperDBContext.Execute(sql, department); //直接传送list对象return result >= 1;#endregion}

4.5 多表多数据批量插入
這里我们采用事物,事物本身有两个特有特性:原子性和统一性,比如:向ABC三个表同时插入,只要有个插入有误都失败,如果不采用事物,采用纯sql插入可能出现数据不一致,AB成功,C失败 。 那我们在DapperDBContext中继续封装一个事物的方法,不知道你现在有没有体会到,我们为啥在中间一层,为了我们根据业务的扩展而却要。 方法可以自己扩展,根据自己业务需要去延伸。。。。。方法中用到的Tuple(元组)方法我们就不做介绍,后期我会整理一篇专门介绍元组的方法以及一些新的特性。事物同样可以满足一个表多条数据插入
/// <summary>/// 多表操作--事务/// </summary>/// <param name="trans"></param>/// <param name="databaseOption"></param>/// <param name="commandTimeout"></param>/// <returns></returns>public static Tuple<bool, string> ExecuteTransaction(List<Tuple<string, object>> trans, int databaseOption = 1, int? commandTimeout = null){if (!trans.Any()) return new Tuple<bool, string>(false, "执行事务SQL语句不能为空!");using (var conn = ConnectionFactory.MySqlConnection()){//开启事务using (var transaction = conn.BeginTransaction()){try{var sb = new StringBuilder("ExecuteTransaction 事务: ");foreach (var tran in trans){sb.Append("SQL语句:" + tran.Item1 + " \n SQL参数: " + JsonConvert.SerializeObject(tran.Item2) + " \n");// 根据业务添加纪录日志 LogHelper.InfoLog("SQL语句:" + tran.Item1 + " \n SQL参数: " + JsonConvert.SerializeObject(tran.Item2) + " \n");//执行事务conn.Execute(tran.Item1, tran.Item2, transaction, commandTimeout);}var sw = new Stopwatch();sw.Start();//提交事务transaction.Commit();sw.Stop();// 根据业务添加纪录日志 LogHelper.InfoLog(sb.ToString() + "耗时:" + sw.ElapsedMilliseconds + (sw.ElapsedMilliseconds > 1000 ? "#####" : string.Empty) + "\n");return new Tuple<bool, string>(true, string.Empty);}catch (Exception ex){//todo:!!!transaction rollback can not work.LogHelper.ErrorLog(ex);//回滚事务transaction.Rollback();conn.Close();conn.Dispose();return new Tuple<bool, string>(false, ex.ToString());}finally{conn.Close();conn.Dispose();}}}}
结果:
public bool Add(List<Department> department, AuthResources authResources){#region 事务:元组形式插入多条数据var param = new List<Tuple<string, object>>();Tuple<string, object> tupel;var sw = new Stopwatch();sw.Start();for (int i = 0; i < 100; i++){tupel = new Tuple<string, object>(@" INSERT INTO Department (ID,EID,Name,Remarks,Description,Notice,ParentId,AddTime,IsDel,UpdateTime) VALUES(@ID,@EID,@Name,@Remarks,@Description,@Notice,@ParentId,@AddTime,@IsDel,@UpdateTime) ", new{ID = Guid.NewGuid(),EID = Guid.NewGuid(),Name = "部门",Remarks = "",Description = "",AddTime = DateTime.Now,IsDel = 0,UpdateTime = DateTime.Now,ParentId = Guid.NewGuid(),Notice = "",});param.Add(tupel);}tupel = new Tuple<string, object>(@" INSERT INTO AuthResources (ID,EID,AuthId,ResourceId,AddTime,IsDel,UpdateTime) VALUES(@ID,@EID,@AuthId,@ResourceId,@AddTime,@IsDel,@UpdateTime) ", new{ID = Guid.NewGuid(),EId = Guid.NewGuid(),AuthId = Guid.NewGuid(),ResourceId = Guid.NewGuid(),AddTime = DateTime.Now,IsDel = 0,UpdateTime = DateTime.Now,});param.Add(tupel); //调用上面我们封装的事物方法:ExecuteTransactionvar result = DapperDBContext.ExecuteTransaction(param).Item1;sw.Stop();return result;#endregion}

4.6 批量更新
1. where in 批量更新, 这时候所有需要更新的值都是一个同样的值


