简介:

dapper 只是一个代码文件,完全开源,你可以在项目里任何位置,来实现数据到对象ORM操作(当然先引用Dapper文件),体积小速度快。使用好处增删改查比较快,不用自己写sql,因为这都是重复技术含量低的工作,还有程序中大量的数据库中读取数据然后创建model,并且为model字段赋值,这都是很轻松的,个人认为Dapper可以看做HelpSQL,甚至比HelperSQL性能高一点。如果你喜欢原生的SQL,那么有喜欢ORM的简单,那你一定钟情于Dapper 并且爱上他。

Dapper的优势:

  1. Dapper是一个轻量级ORM类,代码就是一个SQLMapper.cs文件,编译后一般在40k左右的dll;
  2. Dapper快,为啥说快呢?因为Dapepr速度接近IDataReader,取列表的数据超过DataTable;
  3. Dapper支持什么数据库?支持Mysql,sqlLite,SQLServer,Oracle等一系列数据库,(备注:我个人在在做demo中,就是使用了Mysql,SQLServer,公司和个电脑装的数据库不一样,就都测试了);
  4. Dapper的R支持多表并联的对象,支持一对多,多对多关系,并且没侵入性,想用就用 ;
  5. Dapper原理就是通过Emit反射IDateReader的队列,来快速得到和产生对象;这也是性能高的原因之一;

Dapper语法简单,快速入手。如果面试,让你说出Dapper的好处,为啥用Dapper,上面回答出来,杠杠的。。。。。。。。面试官:我靠,小伙子懂的挺多………

Dapper使用

1. 在NuGet中引用Dapper

Dapper--入门使用 - 图2

Dapper--入门使用 - 图3

2. 新建一个ConnectionFactory类

创建链接对象,這里我们封装两个方法分别获取SQLServerr 和MySQL
  1. public class ConnectionFactory
  2. {
  3. //获取web 中的配置文件
  4. private static readonly string QlwMysqlConnection = ConfigurationManager.AppSettings["sqlconnectionString"];
  5. /// <summary>
  6. /// sqlServer 数据库
  7. /// </summary>
  8. /// <returns></returns>
  9. public static IDbConnection SqlServerConnection()
  10. {
  11. string sqlconnectionString = QlwMysqlConnection; //ConfigurationManager.ConnectionStrings["sqlconnectionString"].ToString();
  12. var connection = new SqlConnection(sqlconnectionString);
  13. if (connection.State == ConnectionState.Closed)
  14. {
  15. connection.Open();
  16. }
  17. return connection;
  18. }
  19. /// <summary>
  20. /// mySQl 数据库
  21. /// </summary>
  22. /// <returns></returns>
  23. public static IDbConnection MySqlConnection()
  24. {
  25. string mysqlconnectionString = QlwMysqlConnection; //ConfigurationManager.ConnectionStrings["mysqlconnectionString"].ToString();
  26. var connection = new MySqlConnection(mysqlconnectionString);
  27. if (connection.State == ConnectionState.Closed)
  28. {
  29. connection.Open();
  30. }
  31. return connection;
  32. }
  33. }

3. Dapper封装方法

(1)先看一下后台:SqlMapper,封装了给我们提供了那些方法:

Dapper--入门使用 - 图4

(2)我们根据上面方法加一层,简单封装,为了业务更加方便: 先说说添加Insert操作,我们对Execute方法进行简单的封装: SqlMapper提供:两个封装Execute:

Dapper--入门使用 - 图5

(3)创建一个DapperDBContext类
  1. public static class DapperDBContext
  2. {
  3. public static List<T> AsList<T>(this IEnumerable<T> source)
  4. {
  5. if (source != null && !(source is List<T>))
  6. return source.ToList();
  7. return (List<T>)source;
  8. }
  9. //参数我们跟后台封装方法保持一致
  10. public static int Execute(string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, int databaseOption = 1)
  11. {
  12. using (var conn = ConnectionFactory.MySqlConnection())
  13. {
  14. var info = "SQL语句:" + sql + " \n SQL参数: " + JsonConvert.SerializeObject(param) + " \n";
  15. // LogHelper.ErrorLog(info); // 可以记录操作
  16. var sw = new Stopwatch(); sw.Start();
  17. var restult = conn.Execute(sql, param, transaction, commandTimeout, commandType);
  18. sw.Stop();
  19. LogHelper.ErrorLog(info + "耗时:" + sw.ElapsedMilliseconds + (sw.ElapsedMilliseconds > 1000 ? "#####" : string.Empty) + "\n"); // 可以记录操作
  20. return restult;
  21. }
  22. }
  23. public static int Execute(CommandDefinition command, int databaseOption = 1)
  24. {
  25. using (var conn = ConnectionFactory.MySqlConnection())
  26. {
  27. var info = " SQL语句:" + command.CommandText + " \n SQL命令类型: " + command.CommandType + " \n";
  28. // LogHelper.Info(info);// 可以记录操作
  29. var sw = new Stopwatch(); sw.Start();
  30. var restult = conn.Execute(command);
  31. sw.Stop();
  32. // LogHelper.Info(info + "耗时:" + sw.ElapsedMilliseconds + (sw.ElapsedMilliseconds > 1000 ? "#####" : string.Empty) + "\n");// 可以记录操作
  33. return restult;
  34. }
  35. }
  36. }

4. Dapper常用CRUD

4.1 Select查询
  1. SQLMapper中QueryMultiple()方法
  1. //
  2. // 摘要:
  3. // Execute a command that returns multiple result sets, and access each in turn: // 上句话的翻译是: 执行一个返回多个结果集的命令,并依次访问每个结果集
  4. public static SqlMapper.GridReader QueryMultiple(this IDbConnection cnn, CommandDefinition command);
  5. //
  6. // 摘要:
  7. // Execute a command that returns multiple result sets, and access each in turn
  8. public static SqlMapper.GridReader QueryMultiple(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);
  9. //
  10. // 摘要:
  11. // Execute a command that returns multiple result sets, and access each in turn
  12. public static Task<SqlMapper.GridReader> QueryMultipleAsync(this IDbConnection cnn, CommandDefinition command);
  13. //
  14. // 摘要:
  15. // Execute a command that returns multiple result sets, and access each in turn
  16. public static Task<SqlMapper.GridReader> QueryMultipleAsync(this IDbConnection cnn, string sql, object param = null,
  17. IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null);
  1. 在DapperDBContext 中加个方法,我们可以根据不同业务扩展方法,
  1. /// <summary>
  2. /// WueryMultiplie 执行一个返回多个结果集的命令,并依次访问每个结果集
  3. /// </summary>
  4. /// <param name="sql"></param>
  5. /// <param name="param"></param>
  6. /// <param name="transaction"></param>
  7. /// <param name="commandTimeout"></param>
  8. /// <param name="commandType"></param>
  9. /// <param name="databaseOption"></param>
  10. /// <returns></returns>
  11. public static Dapper.SqlMapper.GridReader QueryMultiple(string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null, int databaseOption = 1)
  12. {
  13. var conn = ConnectionFactory.MySqlConnection();
  14. var sw = new Stopwatch(); sw.Start();
  15. try
  16. {
  17. // 因为using 的作用域之后,连接自动关闭,
  18. //这里需要说明的是,在数据读取完毕之后,不再需要SqlDataReader时,必须将其进行手动关闭
  19. var restult = conn.QueryMultiple(sql, param, transaction, commandTimeout, commandType);
  20. sw.Stop();
  21. return restult;
  22. }
  23. catch (Exception ex)
  24. {
  25. LogHelper.ErrorLog(ex.ToString());
  26. throw new Exception(ex.ToString());
  27. }
  28. }

注意事项:不知道你在上面代码中有没有遇到一个问题,上篇文章我们封装用到using,这次没有用到,是因为封装过程报错:报错:“阅读器关闭时尝试调用 Read 无效” ,原因也很简单:因为using 的作用域之后,连接自动关闭,这里需要说明的是,在数据读取完毕或者不再需要SqlDataReader时,必须将其进行手动关闭。

  1. SQL调用
  1. /// <summary>
  2. /// 单表查数据
  3. /// </summary>
  4. /// <returns></returns>
  5. public List<Department> select()
  6. {
  7. string sql = @"select *from Department";
  8. var list = DapperDBContext.Query<Department>(sql, null).ToList(); //(多个结果集)为了比较就写一起
  9. var all = selectAll();
  10. var dep = all.Read<Department>().ToList();
  11. var auth = all.Read<AuthResources>().ToList();
  12. return list;
  13. }
  14. /// <summary>
  15. /// 多个结果集
  16. /// </summary>
  17. /// <returns></returns>
  18. public Dapper.SqlMapper.GridReader selectAll()
  19. {
  20. var sql = "select * from Department; select * from AuthResources";
  21. var multiReader = DapperDBContext.QueryMultiple(sql);
  22. return multiReader;
  23. }

效果:

Dapper--入门使用 - 图6Dapper--入门使用 - 图7

4.2 模糊查询

方法1:

  1. db.Query<Remitente>("SELECT *
  2. FROM Remitentes
  3. WHERE Nombre LIKE @n", new { n = "%" + nombre + "%" })
  4. .ToList();

方法2:

Dapper--入门使用 - 图8

4.3 单条数据插入
  1. public class DepartmentRepository
  2. {
  3. /// <summary>
  4. /// 插入单条数据以及多条数据
  5. /// </summary>
  6. /// <param name="department"></param>
  7. /// <returns></returns>
  8. public bool Add(List<Department> department, AuthResources authResources)
  9. {
  10. #region 插入单条数据
  11. 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); ";
  12. var result = DapperDBContext.Execute(sql, department[0]);
  13. return result >= 1;
  14. #endregion
  15. }
  16. }

Dapper--入门使用 - 图9

4.4 单表批量数据插入
直接把列表传进去
  1. // department是100条数据 public bool Add(List<Department> department, AuthResources authResources)
  2. {
  3. #region 插入单条数据
  4. 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); ";
  5. var result = DapperDBContext.Execute(sql, department); //直接传送list对象
  6. return result >= 1;
  7. #endregion
  8. }

Dapper--入门使用 - 图10

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

Dapper--入门使用 - 图11

总结: 1、插入的三种方式就结束了,如果你有更好的方法,欢迎下方留言,一起讨论,本文有不对的方法也多多指出; 2、在做的过程中,还百度相关资料,无意中发现数据遍历可以不用for和foreach, 可以用 Enumerable.Range,已测试性能,很不错,Dapper写完建立新的博客讲解。。。。
4.6 批量更新
1. where in 批量更新, 这时候所有需要更新的值都是一个同样的值

Dapper--入门使用 - 图12

2. 如果每条语句更新的值都不一样呢

Dapper--入门使用 - 图13

参考:https://www.cnblogs.com/Cwj-XFH/p/5855489.html