基于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的空隙时间完成,请大家支持,有好东西我一定会分享的,虽然不一定高大上,但一定实用且项目中有实战过的。

基于Dapper二次封装了一个易用的ORM工具类:SqlDapperUtil的更多相关文章

  1. Android基于Retrofit2.0 +RxJava 封装的超好用的RetrofitClient工具类(六)

    csdn :码小白 原文地址: http://blog.csdn.net/sk719887916/article/details/51958010 RetrofitClient 基于Retrofit2 ...

  2. 封装各种生成唯一性ID算法的工具类

    /** * Copyright (c) 2005-2012 springside.org.cn * * Licensed under the Apache License, Version 2.0 ( ...

  3. 实现一个简单的http请求工具类

    OC自带的http请求用起来不直观,asihttprequest库又太大了,依赖也多,下面实现一个简单的http请求工具类 四个文件源码大致如下,还有优化空间 MYHttpRequest.h(类定义, ...

  4. .Net Framework下对Dapper二次封装迁移到.Net Core2.0遇到的问题以及对Dapper的封装介绍

    今天成功把.Net Framework下使用Dapper进行封装的ORM成功迁移到.Net Core 2.0上,在迁移的过程中也遇到一些很有意思的问题,值得和大家分享一下.下面我会还原迁移的每一个过程 ...

  5. 使用Vue CLI 3将基于element-ui二次封装的组件发布到npm

    前言:之前在网上找的好多都是基于vue-cli 2.x的,而使用vue-cli 3的文章比较少,Vue CLI 3 中文文档,所以我在自己尝试的时候把几篇文章结合了一下,调出来了我想要的模式,也就是V ...

  6. 一个好的Java时间工具类DateTime

    此类的灵感来源于C# 虽然网上有什么date4j,但是jar太纠结了,先给出源码,可以继承到自己的util包中,作为一个资深程序员,我相信都有不少好的util工具类,我也希望经过此次分享,能带动技术大 ...

  7. 分享一个关于jackson的Json工具类

    直接贴代码: import org.codehaus.jackson.map.DeserializationConfig.Feature; import org.codehaus.jackson.ma ...

  8. 一个简单IP防刷工具类, x秒内最多允许y次单ip操作

    IP防刷,也就是在短时间内有大量相同ip的请求,可能是恶意的,也可能是超出业务范围的.总之,我们需要杜绝短时间内大量请求的问题,怎么处理? 其实这个问题,真的是太常见和太简单了,但是真正来做的时候,可 ...

  9. vue-cli4.0 基于 antd-design-vue 二次封装发布到 npm 仓库

    1. 安装 cli npm install -g @vue/cli vue create winyh-ui 2.安装 antd-design-vue cnpm i ant-design-vue --s ...

随机推荐

  1. 自制vbs消息轰炸机

    自制消息轰炸机 目标 做一个简单的,可以自己输入参数的vbs程序 准备 电脑qq 脚本设计成了可以指定发给某个好友轰炸的形式,在写好以后容错性比较强,但这意味着你想换人的话,需要重新改代码 vbs脚本 ...

  2. Elasticsearch 滚动重启 必读

    关键词:elasticsearch , es , 滚动重启 , 禁止分片 由于之前es GC没有怎么调优,结果今天被大量scroll查询查挂了,GC 卡死了.然后为了先恢复给业务使用,也没什么其他办法 ...

  3. LeetCode 33 Search in Rotated Sorted Array [binary search] <c++>

    LeetCode 33 Search in Rotated Sorted Array [binary search] <c++> 给出排序好的一维无重复元素的数组,随机取一个位置断开,把前 ...

  4. 单点登录实现原理(SSO)

    简介 单点登录是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统的保护资源,若用户在某个应用系统中进行注销登录,所有的应用系统都不能再直接访问保护资源,像一些知名的大型网站,如:淘 ...

  5. mysql uodate 报错 You can't specify target table '**' for update in FROM clause

    You can't specify target table 'sc' for update in FROM clause 背景:把“sc”表中“叶平”老师教的课的成绩都更改为此课程的平均成绩: 上面 ...

  6. jstl使用中的错误----基于idea

    第一:首先正确将jstl.jar和standard.jar导入项目的lib目录下,注意两者的版本信息 第二: <%@ taglib prefix="c" uri=" ...

  7. json 的使用 Java对象转json

    1. jsonlib:个人感觉最麻烦的一个需要导入的包也多,代码也相对多一些. 2.Gson:google的 3.FastJson:阿里巴巴的,个人觉得这个比较好,而且据说这个也是性能最好一个. 下面 ...

  8. Dora.Interception,为.NET Core度身打造的AOP框架 [2]:以约定的方式定义拦截器

    上一篇<更加简练的编程体验>提供了最新版本的Dora.Interception代码的AOP编程体验,接下来我们会这AOP框架的编程模式进行详细介绍,本篇文章着重关注的是拦截器的定义.采用“ ...

  9. 【安富莱专题教程第3期】开发板搭建Web服务器,利用花生壳让电脑和手机可以外网远程监控

    说明:1.  开发板Web服务器的设计可以看我们之前发布的史诗级网络教程:链接.2.  需要复杂些的Web设计模板,可以使用我们V6开发板发布的综合Demo:链接.3.  教程中使用的是花生壳免费版, ...

  10. Python的变量声明

    Python 与大多数其它语言一样有局部变量和全局变量之分,但是它没有明显的变量声明.变量通过首次赋值产生,当超出作用范围时自动消亡. Example 1. 定义 myParams 变量 if __n ...