由公司須要使用dapper 同時支持多數據庫 又須要支持實體類 又須要支持sql 還須要支持事務 因此採用了 dapper + dapperExtensions 並配套 生成實體類小工具的方式 mysql
nuget中 下載安裝 Dapper, DapperExtensions.NetCoregit
orcale: Oracle.ManagedDataAccess.Coregithub
SQLite: System.Data.SQLite.Coresql
log4net數據庫
var orcalConn = new OracleConnection(strConn); var orcaleconfig = new DapperExtensionsConfiguration(typeof(AutoClassMapper<>), new List<Assembly>(), new OracleDialect()); var orcaleGenerator = new SqlGeneratorImpl(orcaleconfig); connection = new Database(orcalConn, orcaleGenerator);
注:數據庫不一樣時 改變 這段內容便可json
插入數據使用方式舉例:app
Connection.Insert(list, tran, commandTimeout);
新建core 類庫項目 並引用好所需nuget包ide
增長如下類工具
using DapperExtensions.Mapper; using System; using System.Collections.Generic; using System.Data; using System.Data.SQLite; using System.Text; using Dapper; using DapperExtensions; using System.Reflection; using DapperExtensions.Sql; using Oracle.ManagedDataAccess.Client; using System.Data.SqlClient; using MySql.Data.MySqlClient; namespace CommonHelper { /// <summary> /// 數據庫鏈接輔助類 /// </summary> public class ConnectionFactory { /// <summary> /// 轉換數據庫類型 /// </summary> /// <param name="databaseType">數據庫類型</param> /// <returns></returns> public static DatabaseType GetDataBaseType(string databaseType) { DatabaseType returnValue = DatabaseType.SqlServer; foreach (DatabaseType dbType in Enum.GetValues(typeof(DatabaseType))) { if (dbType.ToString().Equals(databaseType, StringComparison.OrdinalIgnoreCase)) { returnValue = dbType; break; } } return returnValue; } /// <summary> /// 獲取數據庫鏈接 /// </summary> /// <returns></returns> public static Database CreateConnection(string strConn, DatabaseType databaseType = DatabaseType.Oracle) { Database connection = null; //獲取配置進行轉換 switch (databaseType) { case DatabaseType.SqlServer: var sqlConn = new SqlConnection(strConn); var sqlconfig = new DapperExtensionsConfiguration(typeof(AutoClassMapper<>), new List<Assembly>(), new SqlServerDialect()); var sqlGenerator = new SqlGeneratorImpl(sqlconfig); connection = new Database(sqlConn, sqlGenerator); break; case DatabaseType.MySql: var mysqlConn = new MySqlConnection(strConn); var mysqlconfig = new DapperExtensionsConfiguration(typeof(AutoClassMapper<>), new List<Assembly>(), new MySqlDialect()); var mysqlGenerator = new SqlGeneratorImpl(mysqlconfig); connection = new Database(mysqlConn, mysqlGenerator); break; case DatabaseType.Sqlite: var sqlliteConn = new SQLiteConnection(strConn); var sqlliteconfig = new DapperExtensionsConfiguration(typeof(AutoClassMapper<>), new List<Assembly>(), new SqliteDialect()); var sqlliteGenerator = new SqlGeneratorImpl(sqlliteconfig); connection = new Database(sqlliteConn, sqlliteGenerator); break; case DatabaseType.Oracle: var orcalConn = new OracleConnection(strConn); var orcaleconfig = new DapperExtensionsConfiguration(typeof(AutoClassMapper<>), new List<Assembly>(), new OracleDialect()); var orcaleGenerator = new SqlGeneratorImpl(orcaleconfig); connection = new Database(orcalConn, orcaleGenerator); break; } return connection; } } }
using System; using System.Collections.Generic; using System.Data; using System.IO; using System.Text; using System.Threading.Tasks; using Dapper; using DapperExtensions; using Microsoft.Extensions.Configuration; namespace CommonHelper { /// <summary> /// dapper 幫助類 /// </summary> public class DapperHelper : IDapperHelper, IDisposable { private string ConnectionString = string.Empty; private Database Connection = null; /// <summary> /// 初始化 若不傳則默認從appsettings.json讀取Connections:DefaultConnect節點 /// 傳入setting:xxx:xxx形式 則會從指定的配置文件中讀取內容 /// 直接傳入鏈接串則 /// </summary> /// <param name="conn"></param> /// <param name="jsonConfigFileName"> 配置文件名稱</param> public DapperHelper(string conn = "", string jsonConfigFileName = "appsettings.json", DatabaseType databaseType = DatabaseType.Oracle) { var config = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile(jsonConfigFileName, optional: true) .Build(); if (string.IsNullOrEmpty(conn)) { conn = config.GetSection("Connections:DefaultConnect").Value; } else if (conn.StartsWith("setting:")) { conn = config.GetSection(conn.Substring(8)).Value; } ConnectionString = conn; Connection = ConnectionFactory.CreateConnection(ConnectionString, databaseType); } public Database GetConnection() { return Connection; } public IDbTransaction TranStart() { if (Connection.Connection.State == ConnectionState.Closed) Connection.Connection.Open(); return Connection.Connection.BeginTransaction(); } public void TranRollBack(IDbTransaction tran) { tran.Rollback(); if (Connection.Connection.State == ConnectionState.Open) tran.Connection.Close(); } public void TranCommit(IDbTransaction tran) { tran.Commit(); if (Connection.Connection.State == ConnectionState.Open) tran.Connection.Close(); } public bool Delete<T>(T obj, IDbTransaction tran = null, int? commandTimeout = null) where T : class { return Connection.Delete(obj, tran, commandTimeout); } public bool Delete<T>(IEnumerable<T> list, IDbTransaction tran = null, int? commandTimeout = null) where T : class { return Connection.Delete(list, tran, commandTimeout); } public void Dispose() { if (Connection != null) { Connection.Dispose(); } } public T Get<T>(string id, IDbTransaction tran = null, int? commandTimeout = null) where T : class { return Connection.Get<T>(id, tran, commandTimeout); } public IEnumerable<T> GetAll<T>(object predicate = null, IList<ISort> sort = null, IDbTransaction tran = null, int? commandTimeout = null, bool buffered = true) where T : class { return Connection.GetList<T>(predicate, sort, tran, commandTimeout, buffered); } public IEnumerable<T> GetPage<T>(object predicate, IList<ISort> sort, int page, int pagesize, IDbTransaction tran = null, int? commandTimeout = null, bool buffered = true) where T : class { return Connection.GetPage<T>(predicate, sort, page, pagesize, tran, commandTimeout, buffered); } public dynamic Insert<T>(T obj, IDbTransaction tran = null, int? commandTimeout = null) where T : class { return Connection.Insert(obj, tran, commandTimeout); } public void Insert<T>(IEnumerable<T> list, IDbTransaction tran = null, int? commandTimeout = null) where T : class { Connection.Insert(list, tran, commandTimeout); } public bool Update<T>(T obj, IDbTransaction tran = null, int? commandTimeout = null, bool ignoreAllKeyProperties = true) where T : class { return Connection.Update(obj, tran, commandTimeout, ignoreAllKeyProperties); } public bool Update<T>(IEnumerable<T> list, IDbTransaction tran = null, int? commandTimeout = null, bool ignoreAllKeyProperties = true) where T : class { return Connection.Update(list, tran, commandTimeout, ignoreAllKeyProperties); } public List<T> Query<T>(string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null) { return Connection.Connection.Query<T>(sql, param, transaction, buffered, commandTimeout, commandType).AsList(); } public int Execute<T>(string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null) { return Connection.Connection.Execute(sql, param, transaction, commandTimeout, commandType); } } }
using System; using System.Collections.Generic; using System.Text; namespace CommonHelper { /// <summary> /// 數據庫類型定義 /// </summary> public enum DatabaseType { SqlServer, //SQLServer數據庫 MySql, //Mysql數據庫 Oracle, //Oracle數據庫 Sqlite, //SQLite數據庫 } }
using DapperExtensions; using System; using System.Collections.Generic; using System.Data; using System.Text; using System.Threading.Tasks; namespace CommonHelper { public interface IDapperHelper { Database GetConnection(); T Get<T>(string id, IDbTransaction tran = null, int? commandTimeout = null) where T : class; IEnumerable<T> GetAll<T>(object predicate = null, IList<ISort> sort = null, IDbTransaction tran = null, int? commandTimeout = null, bool buffered = true) where T : class; IEnumerable<T> GetPage<T>(object predicate, IList<ISort> sort, int page, int pagesize, IDbTransaction tran = null, int? commandTimeout = null, bool buffered = true) where T : class; dynamic Insert<T>(T obj,IDbTransaction tran = null, int? commandTimeout = null) where T : class; void Insert<T>(IEnumerable<T> list, IDbTransaction tran = null, int? commandTimeout = null) where T : class; bool Update<T>(T obj, IDbTransaction tran = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class; bool Update<T>(IEnumerable<T> list, IDbTransaction tran = null, int? commandTimeout = null, bool ignoreAllKeyProperties = false) where T : class; bool Delete<T>(T obj, IDbTransaction tran = null, int? commandTimeout = null) where T : class; bool Delete<T>(IEnumerable<T> list, IDbTransaction tran = null, int? commandTimeout = null) where T : class; IDbTransaction TranStart(); void TranRollBack(IDbTransaction tran); void TranCommit(IDbTransaction tran); List<T> Query<T>(string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null); int Execute<T>(string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null); } }
using log4net; using log4net.Config; using log4net.Repository; using System; using System.IO; //[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", ConfigFileExtension = "config", Watch = true)] namespace CommonHelper { public static class LogHelper { private static ILoggerRepository repository = LogManager.CreateRepository("ApiLogs"); static LogHelper() { XmlConfigurator.Configure(repository, new FileInfo("log4net.config")); } private static ILog log = LogManager.GetLogger(repository.Name, "LogHelper"); private static ILog log_Normal = LogManager.GetLogger(repository.Name, "LogHelperNormal"); public static void Write(string msg, LogLev lev) { switch (lev) { case LogLev.Debug: log_Normal.Debug(msg); break; case LogLev.Error: log.Error(msg); break; case LogLev.Fatal: log.Fatal(msg); break; case LogLev.Info: log_Normal.Info(msg); break; case LogLev.Warn: log_Normal.Warn(msg); break; default: break; } } public static void Write(string msg, LogLev lev, params object[] parm) { switch (lev) { case LogLev.Debug: log_Normal.DebugFormat(msg, parm); break; case LogLev.Error: log.ErrorFormat(msg, parm); break; case LogLev.Fatal: log.FatalFormat(msg, parm); break; case LogLev.Info: log_Normal.InfoFormat(msg, parm); break; case LogLev.Warn: log_Normal.WarnFormat(msg, parm); break; default: break; } } public static void Write(Exception ex, LogLev lev) { switch (lev) { case LogLev.Debug: log_Normal.Debug(ex); break; case LogLev.Error: log.Error(ex); break; case LogLev.Fatal: log.Fatal(ex); break; case LogLev.Info: log_Normal.Info(ex); break; case LogLev.Warn: log_Normal.Warn(ex); break; default: break; } } public static void Log(Exception ex) { Write("方法:{0} 消息:{1} 類:{2} 堆:{3} ", LogLev.Fatal, ex.TargetSite, ex.Message,ex.Source, ex.StackTrace); } public static void Log(Exception ex,int fmodelid) { Write("方法:{0} 消息:{1} 類:{2} 堆:{3} fmodelid:{4}", LogLev.Fatal, ex.TargetSite, ex.Message, ex.Source, ex.StackTrace,fmodelid); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using log4net; namespace CommonHelper { public enum LogLev { Debug, Error, Fatal, Info, Warn } }
引用類庫項目後調用方式以下:單元測試
在配置文件appsettings.json 中增長
"Connections": { "DefaultConnect": "Data Source=192.168.1.xxx/orcl;User ID=xxx;Password=xxxx;" }
using CommonHelper; using DapperExtensions; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Linq; using System.Threading.Tasks; namespace DapperHelperTest { [TestClass] public class UnitTest1 { /// <summary> /// 基本測試 詳細參考https://github.com/tmsmith/Dapper-Extensions/blob/master/DapperExtensions.Test/IntegrationTests/Oracle/CrudFixture.cs /// </summary> [TestMethod] public void TestMethod1() { using (var dp = new DapperHelper()) { var obj = new USER() { FID = "test222", FNAME = "test", FCREATETIME = DateTime.Now, FREALNAME = "t" }; //增 var insert = dp.Insert(obj); Assert.IsTrue(insert == "test222"); obj.FNAME = "test2"; //改 var update = dp.Update(obj); Assert.IsTrue(update); //取全部帶條件 var predicate = Predicates.Field<USER>(f => f.FNAME, Operator.Eq, "test2"); var allrecords = dp.GetAll<USER>(predicate); Assert.IsTrue(allrecords.Count() > 0); //取 var user2 = dp.Get<USER>("test222"); Assert.IsTrue(user2 != null); //刪 bool isdel = dp.Delete(obj); Assert.IsTrue(isdel); } } /// <summary> /// 測試事務 /// </summary> [TestMethod] public void TestMethod2() { using (var dp = new DapperHelper()) { var tran = dp.TranStart(); var obj = new USER() { FID = "test222", FNAME = "test", FCREATETIME = DateTime.Now, FREALNAME = "t" }; //事務回滾 var insert = dp.Insert(obj, tran); var user2 = dp.Get<USER>("test222", tran); Assert.IsTrue(user2 != null); tran.Rollback(); var user3 = dp.Get<USER>("test222"); Assert.IsTrue(user3 == null); //事務提交 tran = dp.TranStart(); insert = dp.Insert(obj, tran); Assert.IsTrue(user2 != null); tran.Commit(); user3 = dp.Get<USER>("test222"); Assert.IsTrue(user3 != null); //刪除測試數據 bool isdel = dp.Delete(obj); Assert.IsTrue(isdel); } } /// <summary> /// 測試sql /// </summary> [TestMethod] public void TestMethod3() { using (var dp = new DapperHelper()) { var tt = dp.Query<USER>("select * from USER"); } } } }
注: 須要在引用的項目中增長log4net.config文件 並設置始終複製 或者較新則複製
文件參考以下:
<log4net> <logger name="LogHelper"> <level value="ALL" /> <appender-ref ref="Appender" /> </logger> <logger name="LogHelperNormal"> <level value="ALL" /> <appender-ref ref="NormalAppender" /> </logger> <appender name="Appender" type="log4net.Appender.RollingFileAppender"> <!--日誌文件名開頭--> <param name="File" value="Log\\" /> <!--是否追加到文件,默認爲true,一般無需設置--> <param name="AppendToFile" value="true" /> <param name="MaxSizeRollBackups" value="100" /> <param name="MaxFileSize" value="10240" /> <param name="StaticLogFileName" value="false" /> <!--日期的格式,天天換一個文件記錄,如不設置則永遠只記錄一天的日誌,需設置--> <param name="DatePattern" value="yyyyMMdd"_Exception.log"" /> <param name="RollingStyle" value="Date" /> <layout type="log4net.Layout.PatternLayout"> <param name="ConversionPattern" value="<HR COLOR=red>%n異常時間:%d [%t] <BR>%n異常級別:%-5p <BR>%n異 常 類:%c [%x] <BR>%n%m <BR>%n <HR Size=1>" /> </layout> </appender> <appender name="NormalAppender" type="log4net.Appender.RollingFileAppender"> <param name="File" value="Log\\" /> <param name="AppendToFile" value="true" /> <param name="MaxFileSize" value="10240" /> <param name="MaxSizeRollBackups" value="100" /> <param name="StaticLogFileName" value="false" /> <param name="DatePattern" value="yyyyMMdd"_Normal.log"" /> <param name="RollingStyle" value="Date" /> <layout type="log4net.Layout.PatternLayout"> <param name="ConversionPattern" value="<HR COLOR=blue>%n日誌時間:%d [%t] <BR>%n日誌級別:%-5p <BR>%n日 志 類:%c [%x] <BR>%n%m <BR>%n <HR Size=1>" /> </layout> </appender> </log4net>
新建core 控制檯程序
添加appsettings.json
{ "Connections": { "DefaultConnect": "Data Source=192.168.1.xxx/orcl;User ID=xxx;Password=xxx;" }, "Settings": { "NameSpace": "DBModels",//命名空間 "RelativePath": "AuthService/Models",//相對路徑地址 "FullPath": "",//全路徑地址 填寫之後 相對路徑地址失效 "GenerateTables": "USER" //須要生成的表名 不填默認生成所有的表 } }
改變Program.cs 以下(簡易版本 註釋部份內容爲 繼承基類的配置 如須要繼承基類 去除註釋部分代碼便可)
using Microsoft.Extensions.Configuration; using SqlSugar; using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace ModelGeneration { /// <summary> /// 使用sqlsuger 自動生成實體類 /// </summary> class Program { static void Main(string[] args) { var config = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: true) .Build(); var conn = config.GetSection("Connections:DefaultConnect").Value; string path = string.Empty; var relativePath = config.GetSection("Settings:RelativePath").Value; //自動找最外層並 找到更外層 方便附加到其餘項目中 if (!string.IsNullOrEmpty(relativePath)) { var basePath = new DirectoryInfo(Directory.GetCurrentDirectory()); while ((basePath.FullName.Contains(@"\Debug") || basePath.FullName.Contains(@"\bin"))&&!string.IsNullOrEmpty(basePath.FullName)) { basePath=basePath.Parent; } path = Path.Combine(basePath.Parent.FullName, relativePath); } var fullPath= config.GetSection("Settings:FullPath").Value; if (!string.IsNullOrEmpty(fullPath)) path = fullPath; InitModel(conn,config.GetSection("Settings:NameSpace").Value, path, config.GetSection("Settings:GenerateTables").Value); } public static void InitModel(string conn,string namespaceStr, string path,string genaratetables) { try { Console.WriteLine("開始建立"); var tableNames = genaratetables.Split(',').ToList(); for (int i = 0; i < tableNames.Count; i++) { tableNames[i] = tableNames[i].ToLower(); } var suger = GetInstance(conn).DbFirst.SettingClassTemplate(old => { return old.Replace("{Namespace}", namespaceStr);//.Replace("class {ClassName}", "class {ClassName} :BaseEntity");//改變命名空間 }); if (tableNames.Count >= 0) { suger.Where(it => tableNames.Contains(it.ToLower())).IsCreateDefaultValue(); } else { suger.IsCreateDefaultValue(); } //過濾BaseEntity中存在的字段 //var pros = typeof(BaseEntity).GetProperties(); //var list = new List<SqlSugar.IgnoreColumn>(); var tables = suger.ToClassStringList().Keys; //foreach (var item in pros) //{ // foreach (var table in tables) // { // list.Add(new SqlSugar.IgnoreColumn() { EntityName = table, PropertyName = item.Name }); // } //} //suger.Context.IgnoreColumns.AddRange(list); suger.CreateClassFile(path); Console.WriteLine("建立完成"); Console.ReadKey(); } catch (Exception ex) { Console.WriteLine(ex.Message); } } public static SqlSugarClient GetInstance(string conn) { SqlSugarClient db = new SqlSugarClient(new ConnectionConfig() { ConnectionString = conn, DbType = DbType.Oracle, IsAutoCloseConnection = true, IsShardSameThread = true //設爲true相同線程是同一個SqlSugarClient }); db.Ado.IsEnableLogEvent = true; db.Ado.LogEventStarting = (sql, pars) => { }; return db; } } }