簡介:
不知道部落格怎麼去寫去排版,查了好多相關部落格,也根據自己做過項目總結,正好最近搭個微服務架構,順便把搭建微服務架構所運用的知識都進行部落格梳理,為了以後複習,就仔細琢磨寫一下自己在微服務架構中對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寫完建立新的部落格講解。。。。