之前介紹了基於Dapper二次封裝了一個易用的ORM工具類:SqlDapperUtil,這個在.NET FX下還是比較好用的,現在都流行.NET CORE,故我這邊再次進行精簡修改,以便適應.NET CORE並支持依賴注入。
-
提取定義了一個通用訪問數據的接口:
public interface IDbAccesser { void Commit(); bool ExecuteCommand(string sql, object param = null, int? commandTimeout = null, CommandType? commandType = null); T GetDynamicModel<T>(Func<IEnumerable<dynamic>, T> buildModelFunc, string sql, object param = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null); Dictionary<string, dynamic> GetFirstValues(string sql, object param = null, int? commandTimeout = null, CommandType? commandType = null); T GetModel<T>(string sql, object param = null, int? commandTimeout = null, CommandType? commandType = null) where T : class; List<T> GetModelList<T>(string sql, object param = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null) where T : class; List<T> GetMultModelList<T>(string sql, Type[] types, Func<object[], T> map, object param = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null); T GetValue<T>(string sql, object param = null, int? commandTimeout = null, CommandType? commandType = null); void Rollback(); void UseDbTransaction(); }
-
精簡版的Dapper封裝操作類:SqlDapperEasyUtil:
/// <summary> /// 基於Dapper的數據操作類封裝的工具類(簡易版) /// Author:左文俊 /// Date:2019/6/28 /// </summary> public class SqlDapperEasyUtil : IDbAccesser { private readonly string dbConnectionString = null; private const string dbProviderName = "System.Data.SqlClient"; private IDbConnection dbConnection = null; private bool useDbTransaction = false; private IDbTransaction dbTransaction = null; static SqlDapperEasyUtil() { DbProviderFactories.RegisterFactory(dbProviderName, SqlClientFactory.Instance);//.NET CORE需先提前注冊 } #region 私有方法 private IDbConnection GetDbConnection() { bool needCreateNew = false; if (dbConnection == null || string.IsNullOrWhiteSpace(dbConnection.ConnectionString)) { needCreateNew = true; } if (needCreateNew) { var dbProviderFactory = DbProviderFactories.GetFactory(dbProviderName); dbConnection = dbProviderFactory.CreateConnection(); dbConnection.ConnectionString = dbConnectionString; } if (dbConnection.State == ConnectionState.Closed) { dbConnection.Open(); } return dbConnection; } private T UseDbConnection<T>(Func<IDbConnection, T> queryOrExecSqlFunc) { IDbConnection dbConn = null; try { dbConn = GetDbConnection(); if (useDbTransaction && dbTransaction == null) { dbTransaction = GetDbTransaction(); } return queryOrExecSqlFunc(dbConn); } catch { throw; } finally { if (dbTransaction == null && dbConn != null) { CloseDbConnection(dbConn); } } } private void CloseDbConnection(IDbConnection dbConn, bool disposed = false) { if (dbConn != null) { if (disposed && dbTransaction != null) { dbTransaction.Rollback(); dbTransaction.Dispose(); dbTransaction = null; } if (dbConn.State != ConnectionState.Closed) { dbConn.Close(); } dbConn.Dispose(); dbConn = null; } } /// <summary> /// 獲取一個事務對象(如果需要確保多條執行語句的一致性,必需使用事務) /// </summary> /// <param name="il"></param> /// <returns></returns> private IDbTransaction GetDbTransaction(IsolationLevel il = IsolationLevel.Unspecified) { return GetDbConnection().BeginTransaction(il); } #endregion public SqlDapperEasyUtil(string connStr) { dbConnectionString = connStr; } /// <summary> /// 使用事務 /// </summary> public void UseDbTransaction() { useDbTransaction = true; } /// <summary> /// 獲取一個值,param可以是SQL參數也可以是匿名對象 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="sql"></param> /// <param name="param"></param> /// <param name="transaction"></param> /// <param name="commandTimeout"></param> /// <param name="commandType"></param> /// <returns></returns> public T GetValue<T>(string sql, object param = null, int? commandTimeout = null, CommandType? commandType = null) { return UseDbConnection((dbConn) => { return dbConn.ExecuteScalar<T>(sql, param, dbTransaction, commandTimeout, commandType); }); } /// <summary> /// 獲取第一行的所有值,param可以是SQL參數也可以是匿名對象 /// </summary> /// <param name="sql"></param> /// <param name="param"></param> /// <param name="transaction"></param> /// <param name="commandTimeout"></param> /// <param name="commandType"></param> /// <returns></returns> public Dictionary<string, dynamic> GetFirstValues(string sql, object param = null, int? commandTimeout = null, CommandType? commandType = null) { return UseDbConnection((dbConn) => { Dictionary<string, dynamic> firstValues = new Dictionary<string, dynamic>(); List<string> indexColNameMappings = new List<string>(); int rowIndex = 0; using (var reader = dbConn.ExecuteReader(sql, param, dbTransaction, commandTimeout, commandType)) { while (reader.Read()) { if ((++rowIndex) > 1) break; if (indexColNameMappings.Count == 0) { for (int i = 0; i < reader.FieldCount; i++) { indexColNameMappings.Add(reader.GetName(i)); } } for (int i = 0; i < reader.FieldCount; i++) { firstValues[indexColNameMappings[i]] = reader.GetValue(i); } } reader.Close(); } return firstValues; }); } /// <summary> /// 獲取一個數據模型實體類,param可以是SQL參數也可以是匿名對象 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="sql"></param> /// <param name="param"></param> /// <param name="transaction"></param> /// <param name="commandTimeout"></param> /// <param name="commandType"></param> /// <returns></returns> public T GetModel<T>(string sql, object param = null, int? commandTimeout = null, CommandType? commandType = null) where T : class { return UseDbConnection((dbConn) => { return dbConn.QueryFirstOrDefault<T>(sql, param, dbTransaction, commandTimeout, commandType); }); } /// <summary> /// 獲取符合條件的所有數據模型實體類列表,param可以是SQL參數也可以是匿名對象 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="sql"></param> /// <param name="param"></param> /// <param name="transaction"></param> /// <param name="buffered"></param> /// <param name="commandTimeout"></param> /// <param name="commandType"></param> /// <returns></returns> public List<T> GetModelList<T>(string sql, object param = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null) where T : class { return UseDbConnection((dbConn) => { return dbConn.Query<T>(sql, param, dbTransaction, buffered, commandTimeout, commandType).ToList(); }); } /// <summary> /// 獲取符合條件的所有數據並根據動態構建Model類委托來創建合適的返回結果(適用於臨時性結果且無對應的模型實體類的情況) /// </summary> /// <typeparam name="T"></typeparam> /// <param name="buildModelFunc"></param> /// <param name="sql"></param> /// <param name="param"></param> /// <param name="buffered"></param> /// <param name="commandTimeout"></param> /// <param name="commandType"></param> /// <returns></returns> public T GetDynamicModel<T>(Func<IEnumerable<dynamic>, T> buildModelFunc, string sql, object param = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null) { var dynamicResult = UseDbConnection((dbConn) => { return dbConn.Query(sql, param, dbTransaction, buffered, commandTimeout, commandType); }); return buildModelFunc(dynamicResult); } /// <summary> /// 獲取符合條件的所有指定返回結果對象的列表(復合對象【如:1對多,1對1】),param可以是SQL參數也可以是匿名對象 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="sql"></param> /// <param name="types"></param> /// <param name="map"></param> /// <param name="param"></param> /// <param name="transaction"></param> /// <param name="buffered"></param> /// <param name="splitOn"></param> /// <param name="commandTimeout"></param> /// <param name="commandType"></param> /// <returns></returns> public List<T> GetMultModelList<T>(string sql, Type[] types, Func<object[], T> map, object param = null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null, CommandType? commandType = null) { return UseDbConnection((dbConn) => { return dbConn.Query<T>(sql, types, map, param, dbTransaction, buffered, splitOn, commandTimeout, commandType).ToList(); }); } /// <summary> /// 執行SQL命令(CRUD),param可以是SQL參數也可以是要添加的實體類 /// </summary> /// <param name="sql"></param> /// <param name="param"></param> /// <param name="transaction"></param> /// <param name="commandTimeout"></param> /// <param name="commandType"></param> /// <returns></returns> public bool ExecuteCommand(string sql, object param = null, int? commandTimeout = null, CommandType? commandType = null) { return UseDbConnection((dbConn) => { int result = dbConn.Execute(sql, param, dbTransaction, commandTimeout, commandType); return (result > 0); }); } /// <summary> /// 當使用了事務,則最后需要調用該方法以提交所有操作 /// </summary> /// <param name="dbTransaction"></param> public void Commit() { try { if (dbTransaction.Connection != null && dbTransaction.Connection.State != ConnectionState.Closed) { dbTransaction.Commit(); } } catch { throw; } finally { if (dbTransaction.Connection != null) { CloseDbConnection(dbTransaction.Connection); } dbTransaction.Dispose(); dbTransaction = null; useDbTransaction = false; if (dbConnection != null) { CloseDbConnection(dbConnection); } } } /// <summary> /// 當使用了事務,如果報錯或需要中斷執行,則需要調用該方法執行回滾操作 /// </summary> /// <param name="dbTransaction"></param> public void Rollback() { try { if (dbTransaction.Connection != null && dbTransaction.Connection.State != ConnectionState.Closed) { dbTransaction.Rollback(); } } catch { throw; } finally { if (dbTransaction.Connection != null) { CloseDbConnection(dbTransaction.Connection); } dbTransaction.Dispose(); dbTransaction = null; useDbTransaction = false; } } ~SqlDapperEasyUtil() { try { CloseDbConnection(dbConnection, true); } catch { } } }
-
在ASP.NET CORE中應用:
//1.在Startup.ConfigureServices方法注入依賴 //如果在多個並發場景中使用,建議使用:AddTransient services.AddScoped<IDbAccesser>(provider => { string connStr = provider.GetService<IConfiguration>().GetConnectionString("配置連接的name"); return new SqlDapperEasyUtil(connStr); }); //2.在具體的controller、service中通過構造函數注入或其它方式注入獲取實例,如: [Route("PushRealNameCheck")] [HttpPost] public ApiResult PushRealNameCheck([FromServices] RealNameCheckService realNameCheckService, [FromBody]RealNameCheckReqeust realNameCheckReqeust) { return realNameCheckService.PushRealNameCheck(realNameCheckReqeust); } public class RealNameCheckService { private ILogger<RealNameCheckService> logger; private IDbAccesser dbAccesser; public RealNameCheckService(ILogger<RealNameCheckService> logger, IDbAccesser dbAccesser) { this.logger = logger; this.dbAccesser = dbAccesser; } //其它方法代碼(如:PushRealNameCheck方法),在此省略... //若需操作DB,則可使用dbAccesser變即可。 }
如有疑問或好的建議,歡迎評論交流。