基於Dapper二次封裝了一個易用的ORM工具類:SqlDapperUtil

来源:https://www.cnblogs.com/zuowj/archive/2018/09/01/9570956.html
-Advertisement-
Play Games

基於Dapper二次封裝了一個易用的ORM工具類:SqlDapperUtil,把日常能用到的各種CRUD都進行了簡化封裝,讓普通程式員只需關註業務即可,因為非常簡單,故直接貼源代碼,大家若需使用可以直接複製到項目中,該SqlDapperUtil已廣泛用於公司項目中。 ColumnAttributeT ...


基於Dapper二次封裝了一個易用的ORM工具類:SqlDapperUtil,把日常能用到的各種CRUD都進行了簡化封裝,讓普通程式員只需關註業務即可,因為非常簡單,故直接貼源代碼,大家若需使用可以直接複製到項目中,該SqlDapperUtil已廣泛用於公司項目中。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Dapper;
using System.Data;
using System.Data.Common;
using System.Reflection;
using System.IO;
using System.Collections.Concurrent;
using System.Data.SqlClient;

namespace Zuowj.Common
{
    /// <summary>
    /// 基於Dapper的數據操作類封裝的工具類
    /// Author:左文俊
    /// Date:2017/12/11
    /// </summary>
    public class SqlDapperUtil
    {
        private static string dbConnectionStringConfigPath = null;
        private readonly static ConcurrentDictionary<string, bool> dbConnNamesCacheDic = new ConcurrentDictionary<string, bool>();

        private string dbConnectionName = null;
        private string dbConnectionString = null;
        private string dbProviderName = null;
        private IDbConnection dbConnection = null;
        private bool useDbTransaction = false;
        private IDbTransaction dbTransaction = null;


        #region 私有方法

        private IDbConnection GetDbConnection()
        {
            bool needCreateNew = false;
            if (dbConnection == null || string.IsNullOrWhiteSpace(dbConnection.ConnectionString))
            {
                needCreateNew = true;
            }
            else if (!MemoryCacheUtil.Contains(dbConnectionName))
            {
                needCreateNew = true;
            }

            if (needCreateNew)
            {
                dbConnectionString = GetDbConnectionString(dbConnectionName, out dbProviderName);
                var dbProviderFactory = DbProviderFactories.GetFactory(dbProviderName);
                dbConnection = dbProviderFactory.CreateConnection();
                dbConnection.ConnectionString = dbConnectionString;
            }

            if (dbConnection.State == ConnectionState.Closed)
            {
                dbConnection.Open();
            }

            return dbConnection;
        }

        private string GetDbConnectionString(string dbConnName, out string dbProviderName)
        {
            //如果指定的連接字元串配置文件路徑,則創建緩存依賴,一旦配置文件更改就失效,再重新讀取
            string[] connInfos = MemoryCacheUtil.GetOrAddCacheItem(dbConnName, () =>
            {
                var connStrSettings = ConfigUtil.GetConnectionStringForConfigPath(dbConnName, SqlDapperUtil.DbConnectionStringConfigPath);
                string dbProdName = connStrSettings.ProviderName;
                string dbConnStr = connStrSettings.ConnectionString;
                //LogUtil.Info(string.Format("SqlDapperUtil.GetDbConnectionString>讀取連接字元串配置節點[{0}]:{1},ProviderName:{2}", dbConnName, dbConnStr, dbProdName), "SqlDapperUtil.GetDbConnectionString");
                return new[] { EncryptUtil.Decrypt(dbConnStr), dbProdName };
            }, SqlDapperUtil.DbConnectionStringConfigPath);

            dbProviderName = connInfos[1];
            return connInfos[0];
        }


        private T UseDbConnection<T>(Func<IDbConnection, T> queryOrExecSqlFunc)
        {
            IDbConnection dbConn = null;

            try
            {
                Type modelType = typeof(T);
                var typeMap = Dapper.SqlMapper.GetTypeMap(modelType);
                if (typeMap == null || !(typeMap is ColumnAttributeTypeMapper<T>))
                {
                    Dapper.SqlMapper.SetTypeMap(modelType, new ColumnAttributeTypeMapper<T>());
                }

                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);
        }

        private DynamicParameters ToDynamicParameters(Dictionary<string, object> paramDic)
        {
            return new DynamicParameters(paramDic);
        }

        #endregion

        public static string DbConnectionStringConfigPath
        {
            get
            {
                if (string.IsNullOrEmpty(dbConnectionStringConfigPath))//如果沒有指定配置文件,則取預設的配置文件路徑作為緩存依賴路徑
                {
                    dbConnectionStringConfigPath = BaseUtil.GetConfigPath();
                }

                return dbConnectionStringConfigPath;
            }
            set
            {
                if (!string.IsNullOrWhiteSpace(value) && !File.Exists(value))
                {
                    throw new FileNotFoundException("指定的DB連接字元串配置文件不存在:" + value);
                }

                //如果配置文件改變,則可能導致連接字元串改變,故必需清除所有連接字元串的緩存以便後續重新載入字元串
                if (!string.Equals(dbConnectionStringConfigPath, value, StringComparison.OrdinalIgnoreCase))
                {
                    foreach (var item in dbConnNamesCacheDic)
                    {
                        MemoryCacheUtil.RemoveCacheItem(item.Key);
                    }
                }

                dbConnectionStringConfigPath = value;
            }
        }

        public SqlDapperUtil(string connName)
        {
            dbConnectionName = connName;
            if (!dbConnNamesCacheDic.ContainsKey(connName)) //如果靜態緩存中沒有,則加入到靜態緩存中
            {
                dbConnNamesCacheDic[connName] = true;
            }

        }


        /// <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>
        /// 批量轉移數據(利用SqlBulkCopy實現快速大批量插入到指定的目的表及SqlDataAdapter的批量刪除)
        /// </summary>
        public bool BatchMoveData(string srcSelectSql, string srcTableName, List<SqlParameter> srcPrimarykeyParams, string destConnName, string destTableName)
        {

            using (SqlDataAdapter srcSqlDataAdapter = new SqlDataAdapter(srcSelectSql, GetDbConnectionString(dbConnectionName, out dbProviderName)))
            {
                DataTable srcTable = new DataTable();
                SqlCommand deleteCommand = null;
                try
                {
                    srcSqlDataAdapter.AcceptChangesDuringFill = true;
                    srcSqlDataAdapter.AcceptChangesDuringUpdate = false;
                    srcSqlDataAdapter.Fill(srcTable);

                    if (srcTable == null || srcTable.Rows.Count <= 0) return true;

                    string notExistsDestSqlWhere = null;
                    string deleteSrcSqlWhere = null;

                    for (int i = 0; i < srcPrimarykeyParams.Count; i++)
                    {
                        string keyColName = srcPrimarykeyParams[i].ParameterName.Replace("@", "");
                        notExistsDestSqlWhere += string.Format(" AND told.{0}=tnew.{0}", keyColName);
                        deleteSrcSqlWhere += string.Format(" AND {0}=@{0}", keyColName);
                    }

                    string dbProviderName2 = null;
                    using (var destConn = new SqlConnection(GetDbConnectionString(destConnName, out dbProviderName2)))
                    {
                        destConn.Open();

                        string tempDestTableName = "#temp_" + destTableName;
                        destConn.Execute(string.Format("select top 0 * into {0} from {1}", tempDestTableName, destTableName));
                        string destInsertCols = null;
                        using (var destSqlBulkCopy = new SqlBulkCopy(destConn))
                        {
                            try
                            {
                                destSqlBulkCopy.BulkCopyTimeout = 120;
                                destSqlBulkCopy.DestinationTableName = tempDestTableName;
                                foreach (DataColumn col in srcTable.Columns)
                                {
                                    destSqlBulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName);
                                    destInsertCols += "," + col.ColumnName;
                                }

                                destSqlBulkCopy.BatchSize = 1000;
                                destSqlBulkCopy.WriteToServer(srcTable);
                            }
                            catch (Exception ex)
                            {
                                //LogUtil.Error("SqlDapperUtil.BatchMoveData.SqlBulkCopy:" + ex.ToString(), "SqlDapperUtil.BatchMoveData");
                            }

                            destInsertCols = destInsertCols.Substring(1);

                            destConn.Execute(string.Format("insert into {1}({0}) select {0} from {2} tnew where not exists(select 1 from {1} told where {3})",
                                             destInsertCols, destTableName, tempDestTableName, notExistsDestSqlWhere.Trim().Substring(3)), null, null, 100);
                        }
                        destConn.Close();
                    }

                    deleteCommand = new SqlCommand(string.Format("DELETE FROM {0} WHERE {1}", srcTableName, deleteSrcSqlWhere.Trim().Substring(3)), srcSqlDataAdapter.SelectCommand.Connection);
                    deleteCommand.Parameters.AddRange(srcPrimarykeyParams.ToArray());
                    deleteCommand.UpdatedRowSource = UpdateRowSource.None;
                    deleteCommand.CommandTimeout = 200;

                    srcSqlDataAdapter.DeleteCommand = deleteCommand;
                    foreach (DataRow row in srcTable.Rows)
                    {
                        row.Delete();
                    }

                    srcSqlDataAdapter.UpdateBatchSize = 1000;
                    srcSqlDataAdapter.Update(srcTable);
                    srcTable.AcceptChanges();

                    return true;
                }
                catch (Exception ex)
                {
                    //LogUtil.Error("SqlDapperUtil.BatchMoveData:" + ex.ToString(), "SqlDapperUtil.BatchMoveData");
                    return false;
                }
                finally
                {
                    if (deleteCommand != null)
                    {
                        deleteCommand.Parameters.Clear();
                    }
                }
            }

        }

        /// <summary>
        /// 批量複製數據(把源DB中根據SQL語句查出的結果批量COPY插入到目的DB的目的表中)
        /// </summary>
        public TResult BatchCopyData<TResult>(string srcSelectSql, string destConnName, string destTableName, IDictionary<string, string> colMappings, Func<IDbConnection, TResult> afterCoppyFunc)
        {

            using (SqlDataAdapter srcSqlDataAdapter = new SqlDataAdapter(srcSelectSql, GetDbConnectionString(dbConnectionName, out dbProviderName)))
            {
                DataTable srcTable = new DataTable();
                TResult copyResult = default(TResult);
                try
                {
                    srcSqlDataAdapter.AcceptChangesDuringFill = true;
                    srcSqlDataAdapter.AcceptChangesDuringUpdate = false;
                    srcSqlDataAdapter.Fill(srcTable);

                    if (srcTable == null || srcTable.Rows.Count <= 0) return copyResult;


                    string dbProviderName2 = null;
                    using (var destConn = new SqlConnection(GetDbConnectionString(destConnName, out dbProviderName2)))
                    {
                        destConn.Open();
                        string tempDestTableName = "#temp_" + destTableName;
                        destConn.Execute(string.Format("select top 0 * into {0} from {1}", tempDestTableName, destTableName));
                        bool bcpResult = false;
                        using (var destSqlBulkCopy = new SqlBulkCopy(destConn))
                        {
                            try
                            {
                                destSqlBulkCopy.BulkCopyTimeout = 120;
                                destSqlBulkCopy.DestinationTableName = tempDestTableName;
                                foreach (var col in colMappings)
                                {
                                    destSqlBulkCopy.ColumnMappings.Add(col.Key, col.Value);
                                }

                                destSqlBulkCopy.BatchSize = 1000;
                                destSqlBulkCopy.WriteToServer(srcTable);
                                bcpResult = true;
                            }
                            catch (Exception ex)
                            {
                                //LogUtil.Error("SqlDapperUtil.BatchMoveData.SqlBulkCopy:" + ex.ToString(), "SqlDapperUtil.BatchMoveData");
                            }
                        }

                        if (bcpResult)
                        {
                            copyResult = afterCoppyFunc(destConn);
                        }

                        destConn.Close();
                    }

                    return copyResult;
                }
                catch (Exception ex)
                {
                    //LogUtil.Error("SqlDapperUtil.BatchCopyData:" + ex.ToString(), "SqlDapperUtil.BatchCopyData");
                    return copyResult;
                }
            }

        }


        /// <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;
            }
        }

        ~SqlDapperUtil()
        {
            try
            {
                CloseDbConnection(dbConnection, true);
            }
            catch
            { }
        }

    }
}

ColumnAttributeTypeMapper輔助類相關代碼如下:(如果不考慮實體類的屬性與表欄位不一致的情況,如下映射類可以不需要添加,同時SqlDapperUtil中移除相關依賴ColumnAttributeTypeMapper邏輯即可)

using Dapper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace KYExpress.Common
{
    public class ColumnAttributeTypeMapper<T> : FallbackTypeMapper
    {
        public ColumnAttributeTypeMapper()
            : base(new SqlMapper.ITypeMap[]
                {
                    new CustomPropertyTypeMap(
                       typeof(T),
                       (type, columnName) =>
                           type.GetProperties().FirstOrDefault(prop =>
                               prop.GetCustomAttributes(false)
                                   .OfType<ColumnAttribute>()
                                   .Any(attr => attr.Name == columnName)
                               )
                       ),
                    new DefaultTypeMap(typeof(T))
                })
        {
        }
    }

    [AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
    public class ColumnAttribute : Attribute
    {
        public string Name { get; set; }
    }

    public class FallbackTypeMapper : SqlMapper.ITypeMap
    {
        private readonly IEnumerable<SqlMapper.ITypeMap> _mappers;

        public FallbackTypeMapper(IEnumerable<SqlMapper.ITypeMap> mappers)
        {
            _mappers = mappers;
        }


        public ConstructorInfo FindConstructor(string[] names, Type[] types)
        {
            foreach (var mapper in _mappers)
            {
                try
                {
                    ConstructorInfo result = mapper.FindConstructor(names, types);
                    if (result != null)
                    {
                        return result;
                    }
                }
                catch (NotImplementedException)
                {
                }
            }
            return null;
        }

        public SqlMapper.IMemberMap GetConstructorParameter(ConstructorInfo constructor, string columnName)
        {
            foreach (var mapper in _mappers)
            {
                try
                {
                    var result = mapper.GetConstructorParameter(constructor, columnName);
                    if (result != null)
                    {
                        return result;
                    }
                }
                catch (NotImplementedException)
                {
                }
            }
            return null;
        }

        public SqlMapper.IMemberMap GetMember(string columnName)
        {
            foreach (var mapper in _mappers)
            {
                try
                {
                    var result = mapper.GetMember(columnName);
                    if (result != null)
                    {
                        return result;
                    }
                }
                catch (NotImplementedException)
                {
                }
            }
            return null;
        }


        public ConstructorInfo FindExplicitConstructor()
        {
            return _mappers
                .Select(mapper => mapper.FindExplicitConstructor())
                .FirstOrDefault(result => result != null);
        }
    }

}

使用示例方法如下:

 1.先來模擬各種查詢數據(由於是直接寫模擬SQL輸出,故沒有條件,也便於大家COPY後直接可以測試結果)

            //實例化SqlDapperUtil對象,構造函數是config文件中的connectionStrings的Name名
            var dapper = new SqlDapperUtil("LmsConnectionString");

            //查詢1個值
            DateTime nowTime = dapper.GetValue<DateTime>("select getdate() as nowtime");


            //查詢1行值,並轉換成字典(這對於臨時查詢多個欄位而無需定義實體類有用)
            Dictionary<string, dynamic> rowValues = dapper.GetFirstValues("select 0 as col0,1 as col1,2 as col2");


            //查詢1行並返回實體類
            Person person = dapper.GetModel<Person>("select '張三' as Name,22 as Age,'2018-1-1' as BirthDay,'中國廣東深圳' as HomeAddr");


            //查詢1行表欄位與實體類屬性不一致映射
            Person person2 = dapper.GetModel<Person>("select '張三' as Name,22 as Age,'2018-1-1' as BirthDay,'中國廣東深圳' as HomeAddress");


            //查詢多行返回實體集合
            var persons = dapper.GetModelList<Person>(@"select '張三' as Name,22 as Age,'2018-1-1' as BirthDay,'中國廣東深圳' as HomeAddr union all
                                                                            select '李四' as Name,25 as Age,'2018-10-1' as BirthDay,'中國廣東深圳' as HomeAddress union all
                                                                            select '王五' as Name,35 as Age,'1982-10-1' as BirthDay,'中國廣東廣州' as HomeAddress
                                                                        ");


            //查詢多行返回1對1關聯實體結果集
            var personWithCarResult = dapper.GetMultModelList<Person>(@"select t1.*,t2.* from
                                                                                                    (select '張三' as Name,22 as Age,'2018-1-1' as BirthDay,'中國廣東深圳' as HomeAddr union all
                                                                                                    select '李四' as Name,25 as Age,'2018-10-1' as BirthDay,'中國廣東深圳' as HomeAddress union all
                                                                                                    select '王五' as Name,35 as Age,'1982-10-1' as BirthDay,'中國廣東廣州' as HomeAddress)as t1 inner join
                                                                                                    (
                                                                                                    select '張三' as DriverName,'大眾' as Brand,'2018-8-8' as ManufactureDate union all
                                                                                                    select '李四' as DriverName,'賓士' as Brand,'2018-1-8' as ManufactureDate union all
                                                                                                    select '王五' as DriverName,'奧迪' as Brand,'2017-8-8' as ManufactureDate
                                                                                                    )as t2
                                                                                                    on t1.Name=t2.DriverName
                                                                        ", new[] { typeof(Person), typeof(CarInfo) }, (objs) =>
                                                                         {
                                                                             Person personItem = objs[0] as Person;
                                                                             CarInfo carItem = objs[1] as CarInfo;
                                                                             personItem.Car = carItem;
                                                                             return personItem;
                                                                         }, splitOn: "DriverName");




            //查詢多行返回1對多關聯實體結果=personWithManyCars
            List<Person> personWithManyCars = new List<Person>();
            dapper.GetMultModelList<Person>(@"select t1.*,t2.* from
                                                                                                    (select '張三' as Name,22 as Age,'2018-1-1' as BirthDay,'中國廣東深圳' as HomeAddr union all
                                                                                                    select '李四' as Name,25 as Age,'2018-10-1' as BirthDay,'中國廣東深圳' as HomeAddress union all
                                                                                                    select '王五' as Name,35 as Age,'1982-10-1' as BirthDay,'中國廣東廣州' as HomeAddress)as t1 inner join
                                                                                                    (
                                                                                                    select '張三' as DriverName,'大眾' as Brand,'2018-8-8' as ManufactureDate union all
                                                                                                    select '張三' as DriverName,'賓士' as Brand,'2018-1-8' as ManufactureDate union all
                                                                                                    select '張三' as DriverName,'奧迪' as Brand,'2017-8-8' as ManufactureDate
                                                                                                    )as t2
                                                                                                    on t1.Name=t2.DriverName
                                                                        ", new[] { typeof(Person), typeof(CarInfo) }, (objs) =>
                                                                        {
                                                                            Person personItem = objs[0] as Person;
                                                                            CarInfo carItem = objs[1] as CarInfo;

                                                                            Person personItemMain = personWithManyCars.FirstOrDefault(p => p.Name == personItem.Name);
                                                                            if (personItemMain == null)
                                                                            {
                                                                                personItem.Cars = new List<CarInfo>();
                                                                                personItemMain = personItem;
                                                                                personWithManyCars.Add(personItemMain);
                                                                            }

                                                                            personItemMain.Cars.Add(carItem);
                                                                            return personItemMain;

                                                                        }, splitOn: "DriverName");

2.下麵是演示如何進行增、刪、改以及動態查詢的情況:

            //使用事務創建多張表,多條SQL語句寫在一起
            try
            {
                dapper.UseDbTransaction();
                dapper.ExecuteCommand(@"create table T_Person(Name nvarchar(20) primary key,Age int,BirthDay datetime,HomeAddress nvarchar(200));
                                                    create table T_CarInfo(DriverName nvarchar(20) primary key,Brand nvarchar(50),ManufactureDate datetime)");
                dapper.Commit();
            }
            catch (Exception ex)
            {
                dapper.Rollback();
                //記日誌
            }

            //使用事務批量插入多張表的多個記錄,多條SQL分多次執行(參數支持批量集合對象傳入,無需迴圈)
            try
            {
                dapper.UseDbTransaction();
                dapper.ExecuteCommand(@"insert into T_Person
select N'張三' as Name,22 as Age,'2018-1-1' as BirthDay,N'中國廣東深圳' as HomeAddress union all
select N'李四' as Name,25 as Age,'2018-10-1' as BirthDay,N'中國廣東深圳' as HomeAddress union all
select N'王五' as Name,35 as Age,'1982-10-1' as BirthDay,N'中國廣東廣州' as HomeAddress");


                var carInfos = dapper.GetModelList<CarInfo>(@"
select N'張三' as DriverName,N'大眾' as Brand,'2018-8-8' as ManufactureDate union all
select N'李四' as DriverName,N'賓士' as Brand,'2018-1-8' as ManufactureDate union all
select N'王五' as DriverName,N'奧迪' as Brand,'2017-8-8' as ManufactureDate");

                dapper.ExecuteCommand(@"insert into T_CarInfo(DriverName,Brand,ManufactureDate) Values(@DriverName,@Brand,@ManufactureDate)", carInfos);

                dapper.Commit();
            }
            catch (Exception ex)
            {
                dapper.Rollback();
                //記日誌
            }

            //執行刪除,有參數,參數可以是實體類、匿名對象、字典(如有需要,可以是集合,以支持批量操作)
            bool deleteResult = dapper.ExecuteCommand("delete from T_CarInfo where DriverName=@DriverName", new { DriverName = "李四" });

            //構建動態執行SQL語句(以下是更新,查詢類似)
            StringBuilder updateSqlBuilder = new StringBuilder();
            var updateParams = new Dictionary<string, object>();

            if (1 == 1)
            {
                updateSqlBuilder.Append(",Age=@Age");
                updateParams["Age"] = 20;
            }

            if (2 == 2)
            {
                updateSqlBuilder.Append(",BirthDay=@BirthDay");
                updateParams["BirthDay"] = Convert.ToDateTime("2010-1-1");
            }

            if (3 == 3)
            {
                updateSqlBuilder.Append(",HomeAddress=@HomeAddress");
                updateParams["HomeAddress"] = "中國北京天安門";
            }

            string updateSql = string.Concat("update T_Person set ", updateSqlBuilder.ToString().TrimStart(','), "  where  Name=@Name");
            updateParams["Name"] = "張三";

            bool updateResult = dapper.ExecuteCommand(updateSql, updateParams);

            //查詢返回動態自定義結果,之所以不直接返回Dynamic就好,是因為可讀性差,故儘可能的在執行後就轉成指定的類型
            Tuple<string, int> hasCarInfo = dapper.GetDynamicModel<Tuple<string, int>>((rs) =>
            {
                var result = rs.First();
                return Tuple.Create<string, int>(result.Name, result.CarCount);
            }, @"select a.Name,count(b.DriverName) as CarCount from T_Person a left join T_CarInfo b on a.Name=b.DriverName where a.Name=@Name group by a.Name", new { Name = "張三" });

3.還有兩個方法:BatchCopyData、BatchMoveData,這是特殊封裝的,不是基於Dapper而是基於原生的Ado.net及BCP,目的是快速大量跨DB跨表COPY數據或轉移數據,使用也不複雜,建議想瞭解的網友可以查看我以往的文章

以上示例方法用到了兩個類,如下:

        class Person
        {
            public string Name { get; set; }


            public int Age { get; set; }

            public DateTime BirthDay { get; set; }

            [Column(Name = "HomeAddress")]
            public string HomeAddr { get; set; }

            public CarInfo Car { get; set; }

            public List<CarInfo> Cars { get; set; }
        }

        class CarInfo
        {
            public string Brand { get; set; }

            public DateTime ManufactureDate { get; set; }

            public string DriverName { get; set; }
        }

SqlDapperUtil類中依賴了之前我封裝的類:如:MemoryCacheUtil(本地記憶體依賴緩存實用工具類)、ConfigUtil(配置文件管理工具類)、EncryptUtil(加密工具類),如果項目中不想引用這些類,可以移除或改成其它方法即可。

 另外說明一下,為了防止和減少因DB連接未及時釋放導致的連接池不足等原因,故預設執行所有的CRUD方法都是用完即釋放,但有一種情況不會釋放就是使用了事務,若使用事務,則必需配套使用:UseDbTransaction、Commit、或失敗執行Rollback,否則可能導致未能及時釋放對象,當然最終當SqlDapperUtil實例被回收後事務若沒有提交或回滾,會強制執行回滾操作並釋放事務及連接對象,防止可能的資源浪費情況。

本來早就想總結一下這篇文章,但一直由於工作太忙沒有時間,今天利用加班研究.NET CORE的空隙時間完成,請大家支持,有好東西我一定會分享的,雖然不一定高大上,但一定實用且項目中有實戰過的。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 安裝小白_Shawshank_之安裝pycharm2017教程 一、準備工作 01、大家可以自行在Jetbrains官網中下載各種版本,推薦最新的版本(免費) 官網網址:https://www.jetbrains.com/pycharm/download/#section=windows 02、或者 ...
  • 指出了《Python游戲編程入門》[美] Jonathan S·Harbour 著 一書中第四章測試打字速度程式原書代碼的錯誤。 ...
  • 一、對象與類 類:類是一個模版,它描述了一類對象的行為和狀態。 <!--?xml version="1.0" encoding="UTF-8"?--> 上面一段代碼就定義了一個animal類,它在內部規定了一類對象段狀態/屬性(color,size)等。同時還規定了它可以進行什麼樣的動作(eat,s ...
  • 上一篇博文談了談股票預測方面的問題,這一篇就談談外匯交易吧。 對沖是金融領域的常見操作之一,即利用市場的不對稱性,在不同市場進行方向相反的交易來保證穩定收益。我是在觀看了李永樂老師對足彩對沖的原理講解之後(http://www.iqiyi.com/w_19rz0551xx.html),才有了這個想法 ...
  • 題意 給出一個$k$,構造一個無向圖,使得每個點的度數為$k$,且存在一個橋 Sol 神仙題 一篇寫的非常好的博客:http://www.cnblogs.com/mangoyang/p/9302269.html 我簡單的來說一下構造過程 首先$n$是偶數的時候無解 奇數的時候:我們拿出兩個點作為橋 ...
  • Spring MVC高級技術包括但不限於web.xml配置、異常處理、跨重定向請求傳遞數據 1、web.xml文件的配置 ContextLoaderListener是根容器,DispatcherServlet是子容器。父容器中管理的bean可以被子容器引用,反之,不行。它們都從各自的xml文件初始化 ...
  • ROW_NUMBER() OVER (ORDER BY (select Null)) AS Id entity framework 查詢中有這句會有異常 ...
  • 隨著ASP.NET Aries的普及,剛好也有點閑空,趕緊把Excel導入功能的教程補上。 Excel導入功能,分為四篇:單表配置(上)、多表高級配置(中)、配置規則(下)、代碼編寫(番外篇)。 本篇介紹單表配置功能。 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...