Dapper介紹
簡介:
不知道博客怎么去寫去排版,查了好多相關博客,也根據自己做過項目總結,正好最近搭個微服務框架,順便把搭建微服務框架所運用的知識都進行博客梳理,為了以后復習,就仔細琢磨寫一下自己在微服務框架中對Dapepr的理解以及項目中應用。 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的隊列,來快速得到和產生對象;這也是性能高的原因之一; 6、Dapper語法簡單,快速入手。
如果面試,讓你說出Dapper的好處,為啥用Dapper,上面回答出來,杠杠的。。。。。。。。
面試官:我靠,小伙子懂的挺多.........
在超過500次poco serialization的過程中所表現的性能,我們發現dapper是第二名,當然第一名誰也無法超越,越底層的當然久越快,同時也就越麻煩。
Dapper代碼應用
第一步:
在NuGet中引用Dapper
第二步:
新建一個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; } }
第三步:
(1)先看一下后台:SqlMapper,封裝了給我們提供了那些方法:
(2)我們根據上面方法加一層,簡單封裝,為了業務更加方便:
先說說添加Insert操作,我們對Execute方法進行簡單的封裝:
SqlMapper提供:兩個封裝Execute:
(3)、創建一個DapperDBContext類
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.1)、單條數據插入:
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.2)、單表批量數據插入:
// 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.3)、多表多數據批量插入:
這里我們采用事物,事物本身有兩個特有特性:原子性和統一性,比如:向ABC三個表同時插入,只要有個插入有誤都失敗,如果不采用事物,采用純sql插入可能出現數據不一致,AB成功,C失敗 。
那我們在DapperDBContext中繼續封裝一個事物的方法,不知道你現在有沒有體會到,我們為啥在中間一層,為了我們根據業務的擴展而卻要。
方法可以自己擴展,根據自己業務需要去延伸。。。。。
/// <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(); } } } }
方法中用到的Tuple(元組)方法我們就不做介紹,后期我會整理一篇專門介紹元組的方法以及一些新的特性。事物同樣可以滿足一個表多條數據插入
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);
//調用上面我們封裝的事物方法:ExecuteTransaction var result = DapperDBContext.ExecuteTransaction(param).Item1; sw.Stop(); return result; #endregion }
結果:
總結:(Dapper 還沒結束,下篇正在書寫中。。。。。。。)
1、插入的三種方式就結束了,如果你有更好的方法,歡迎下方留言,一起討論,本文有不對的方法也多多指出;
2、在做的過程中,還百度相關資料,無意中發現數據遍歷可以不用for和foreach,
可以用 Enumerable.Range,已測試性能,很不錯,Dapper寫完建立新的博客講解。。。。
手動寫東西,你會發現好多問題,大家一起邊學習邊總結,雖然寫博客很費事,但是確實能收入不少東西,最起碼你寫的得到別人認可,
看得懂,如果還能推薦一下,心理滿滿的小激動,哈哈哈哈,好比:你學外語,不去跟別人說,溝通,怎么知道學的怎么樣,博客園就是這個平台.........
- 博主是利用讀書、參考、引用、抄襲、復制和粘貼等多種方式打造成自己的純鍍 24k 文章,請原諒博主成為一個無恥的文檔搬運工!
- 小弟剛邁入博客編寫,文中如有不對,歡迎用板磚扶正,希望給你有所幫助。