關於Dapper的介紹,我想不少人都對它有必定的瞭解,這個相似一個輕型的ORM框架是目前應用很是火的一個東西,聽說各方面的性能都不錯,並且能夠支持多種數據庫,在開始介紹這個文章以前,我花了很多功夫來學習了Dapper 的相關使用。Dapper.Contrib是對Dapper的進一步封裝,使對象的基本增刪改查等操做進一步簡化,我作了一個案例使用Dapper.Contrib 開發.net core程序,測試它對多種數據庫的處理。sql
前面介紹過,Dapper.Contrib是對Dapper的進一步封裝,使對象的基本增刪改查等操做進一步簡化。數據庫
它主要是經過特性映射的方式實現自定義類和數據庫之間的關係處理,以下是實體類的定義信息。json
[Table("T_Customer")] public class CustomerInfo { [ExplicitKey]//非自增加的用此標識 public virtual string ID { get; set; } public virtual string Name { get; set; } public virtual int Age { get; set; } public virtual string Creator { get; set; } public virtual DateTime CreateTime { get; set; } }
Dapper.Contrib的全部實體配置選項app
經過定義好實體類和數據庫表的映射關係,就能夠經過強類型處理相關的接口了,以下所示。框架
T Get<T>(id); IEnumerable<T> GetAll<T>(); int Insert<T>(T obj); int Insert<T>(Enumerable<T> list); bool Update<T>(T obj); bool Update<T>(Enumerable<T> list); bool Delete<T>(T obj); bool Delete<T>(Enumerable<T> list); bool DeleteAll<T>();
這樣經過映射指定表名或者字段信息後,就能夠知道類和表之間的關係,能夠封裝對應的強類型處理接口了。異步
咱們建立一個空白的.net core程序框架後,就在它的基礎上作一些Dapper的數據庫測試。async
首先爲了考慮多數據庫的處理,咱們須要建立一個配置文件,並能夠動態配置不一樣的數據庫,配置文件appSettings.json以下所示。sqlserver
上面我配置了多種數據庫的鏈接字符串,而且經過動態指定節點名稱和數據庫類型,來實現對項目指向不一樣數據庫的訪問。性能
例如咱們準備須要讓Dapper支持咱們常見的數據庫類型,以下定義數據庫類型。學習
/// <summary> /// 數據庫類型定義 /// </summary> public enum DatabaseType { SqlServer, //SQLServer數據庫 MySql, //Mysql數據庫 Npgsql, //PostgreSQL數據庫 Oracle, //Oracle數據庫 Sqlite, //SQLite數據庫 DB2 //IBM DB2數據庫 }
對於不一樣的數據庫信息,咱們須要根據不一樣的配置鏈接字符串,並建立對應的數據庫鏈接對象供Dapper使用,如對於SQLServer的數據庫,那麼建立的是SqlConnection對象,對於Mysql,建立的是MySqlConnection鏈接對象,對於PostgreSQL對應的是NpgsqlConnection,以此類推。而Dapper則經過對鏈接對象的擴展實現了多種數據請求。
對於多數據庫的支持,咱們須要統一解析配置內容appSetting.json的內容,並返回不一樣數據庫的鏈接對象,以下是鏈接工廠的統一處理方式,經過 CreateConnection() 返回配置的鏈接對象。
/// <summary> /// 數據庫鏈接輔助類 /// </summary> public class ConnectionFactory { /// <summary> /// 轉換數據庫類型 /// </summary> /// <param name="databaseType">數據庫類型</param> /// <returns></returns> private 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 IDbConnection CreateConnection() { IDbConnection connection = null; //獲取配置進行轉換 var type = AppConfig.GetConfig("ComponentDbType"); var dbType = GetDataBaseType(type); //DefaultDatabase 根據這個配置項獲取對應鏈接字符串 var database = AppConfig.GetConfig("DefaultDatabase"); if (string.IsNullOrEmpty(database)) { database = "sqlserver";//默認配置 } var strConn = AppConfig.Configuration.GetConnectionString(database); switch (dbType) { case DatabaseType.SqlServer: connection = new System.Data.SqlClient.SqlConnection(strConn); break; case DatabaseType.MySql: connection = new MySql.Data.MySqlClient.MySqlConnection(strConn); break; case DatabaseType.Npgsql: connection = new Npgsql.NpgsqlConnection(strConn); break; case DatabaseType.Sqlite: connection = new SQLiteConnection(strConn); break; case DatabaseType.Oracle: connection = new Oracle.ManagedDataAccess.Client.OracleConnection(strConn); //connection = new System.Data.OracleClient.OracleConnection(strConn); break; case DatabaseType.DB2: //connection = new System.Data.OleDb.OleDbConnection(strConn); break; } return connection; } }
有了數據庫對象工廠,咱們的配置就能夠動態化了。
下面咱們來看看,得到這些鏈接對象後,如何經過Dapper.Contrib來獲取對應的對象了,下面的類是常規的對數據庫信息的處理,包括常規的增刪改查等基礎接口。
/// <summary> /// 常規的數據訪問層 /// </summary> public class Customer { public IDbConnection Connection { get { var connection = ConnectionFactory.CreateConnection(); connection.Open(); return connection; } } public IEnumerable<CustomerInfo> GetAll() { using (IDbConnection dbConnection = Connection) { return dbConnection.GetAll<CustomerInfo>(); //return dbConnection.Query<CustomerInfo>("SELECT * FROM T_Customer"); } } public CustomerInfo FindByID(string id) { using (IDbConnection dbConnection = Connection) { return dbConnection.Get<CustomerInfo>(id); //string query = "SELECT * FROM T_Customer WHERE ID = @Id"; //return dbConnection.Query<CustomerInfo>(query, new { Id = id }).FirstOrDefault(); } } public bool Insert(CustomerInfo info) { bool result = false; using (IDbConnection dbConnection = Connection) { result = dbConnection.Insert(info) > 0; result = true; //string query = "INSERT INTO T_Customer (ID, Name, Age, Creator, CreateTime)" // + " VALUES(@ID, @Name, @Age, @Creator, @CreateTime)"; //result = dbConnection.Execute(query, info) > 0; } return result; } public bool Update(CustomerInfo prod) { bool result = false; using (IDbConnection dbConnection = Connection) { result = dbConnection.Update(prod); //string query = "UPDATE T_Customer SET Name = @Name," // + " Age = @Age, Creator= @Creator, CreateTime=@CreateTime" // + " WHERE ID = @ID"; //result = dbConnection.Execute(query, prod) > 0; } return result; } public bool Delete(string id) { bool result = false; using (IDbConnection dbConnection = Connection) { result = dbConnection.Delete(new CustomerInfo { ID = id }); //string query = "DELETE FROM T_Customer WHERE ID = @Id"; //result = dbConnection.Execute(query, new { ID = id }) > 0; } return result; } public bool DeleteAll() { bool result = false; using (IDbConnection dbConnection = Connection) { result = dbConnection.DeleteAll<CustomerInfo>(); //string query = "DELETE FROM T_Customer WHERE ID = @Id"; //result = dbConnection.Execute(query, new { ID = id }) > 0; } return result; } }
其中的備註部分的代碼是等同於上面的執行代碼的,是Dapper 的SQL版本的一種處理方式。
咱們看到,對於Customer表來講,使用對象的接口處理,咱們已經隔離了不少硬編碼的SQL處理,不過咱們還能夠對它進行進一步的優化處理。
咱們定義一個通用的BaseDAL來剝離常規的增刪改查處理,而且把同步和異步的操做分來兩個文件來管理,同步處理的基類以下代碼所示。
/// <summary> /// 數據庫訪問基類 /// </summary> /// <typeparam name="T">實體類類型</typeparam> public partial class BaseDAL<T> where T : class { /// <summary> /// 對象的表名 /// </summary> public string TableName { get; set; } /// <summary> /// 主鍵屬性對象 /// </summary> public PropertyInfo PrimaryKey { get; set; } public BaseDAL() { this.TableName = EntityHelper.GetTableName(typeof(T)); this.PrimaryKey = EntityHelper.GetSingleKey<T>(); } /// <summary> /// 數據庫鏈接 /// </summary> protected IDbConnection Connection { get { var connection = ConnectionFactory.CreateConnection(); connection.Open(); return connection; } } /// <summary> /// 返回數據庫全部的對象集合 /// </summary> /// <returns></returns> public IEnumerable<T> GetAll() { using (IDbConnection dbConnection = Connection) { return dbConnection.GetAll<T>(); } } /// <summary> /// 查詢數據庫,返回指定ID的對象 /// </summary> /// <param name="id">主鍵的值</param> /// <returns></returns> public T FindByID(object id) { using (IDbConnection dbConnection = Connection) { return dbConnection.Get<T>(id); } } /// <summary> /// 插入指定對象到數據庫中 /// </summary> /// <param name="info">指定的對象</param> /// <returns></returns> public bool Insert(T info) { bool result = false; using (IDbConnection dbConnection = Connection) { dbConnection.Insert(info); result = true; } return result; } /// <summary> /// 插入指定對象集合到數據庫中 /// </summary> /// <param name="list">指定的對象集合</param> /// <returns></returns> public bool Insert(IEnumerable<T> list) { bool result = false; using (IDbConnection dbConnection = Connection) { result = dbConnection.Insert(list) > 0; } return result; } /// <summary> /// 更新對象屬性到數據庫中 /// </summary> /// <param name="info">指定的對象</param> /// <returns></returns> public bool Update(T info) { bool result = false; using (IDbConnection dbConnection = Connection) { result = dbConnection.Update(info); } return result; } /// <summary> /// 更新指定對象集合到數據庫中 /// </summary> /// <param name="list">指定的對象集合</param> /// <returns></returns> public bool Update(IEnumerable<T> list) { bool result = false; using (IDbConnection dbConnection = Connection) { result = dbConnection.Update(list); } return result; } /// <summary> /// 從數據庫中刪除指定對象 /// </summary> /// <param name="info">指定的對象</param> /// <returns></returns> public bool Delete(T info) { bool result = false; using (IDbConnection dbConnection = Connection) { result = dbConnection.Delete(info); } return result; } /// <summary> /// 從數據庫中刪除指定對象集合 /// </summary> /// <param name="list">指定的對象集合</param> /// <returns></returns> public bool Delete(IEnumerable<T> list) { bool result = false; using (IDbConnection dbConnection = Connection) { result = dbConnection.Delete(list); } return result; } /// <summary> /// 根據指定對象的ID,從數據庫中刪除指定對象 /// </summary> /// <param name="id">對象的ID</param> /// <returns></returns> public bool Delete(object id) { bool result = false; using (IDbConnection dbConnection = Connection) { string query = string.Format("DELETE FROM {0} WHERE {1} = @id", TableName, PrimaryKey.Name); var parameters = new DynamicParameters(); parameters.Add("@id", id); result = dbConnection.Execute(query, parameters) > 0; } return result; } /// <summary> /// 從數據庫中刪除全部對象 /// </summary> /// <returns></returns> public bool DeleteAll() { bool result = false; using (IDbConnection dbConnection = Connection) { result = dbConnection.DeleteAll<T>(); } return result; } }
異步類的代碼以下所示。
/// <summary> /// 數據庫訪問基類 /// </summary> /// <typeparam name="T">實體類類型</typeparam> public partial class BaseDAL<T> where T : class { /// <summary> /// 返回數據庫全部的對象集合 /// </summary> /// <returns></returns> public virtual async Task<IEnumerable<T>> GetAllAsync() { using (IDbConnection dbConnection = Connection) { return await dbConnection.GetAllAsync<T>(); } } /// <summary> /// 查詢數據庫,返回指定ID的對象 /// </summary> /// <param name="id">主鍵的值</param> /// <returns></returns> public virtual async Task<T> FindByIDAsync(object id) { using (IDbConnection dbConnection = Connection) { return await dbConnection.GetAsync<T>(id); } } /// <summary> /// 插入指定對象到數據庫中 /// </summary> /// <param name="info">指定的對象</param> /// <returns></returns> public virtual async Task<bool> InsertAsync(T info) { bool result = false; using (IDbConnection dbConnection = Connection) { await dbConnection.InsertAsync(info); result = true; } return await Task<bool>.FromResult(result); } /// <summary> /// 插入指定對象集合到數據庫中 /// </summary> /// <param name="list">指定的對象集合</param> /// <returns></returns> public virtual async Task<bool> InsertAsync(IEnumerable<T> list) { using (IDbConnection dbConnection = Connection) { return await dbConnection.InsertAsync(list) > 0; } } /// <summary> /// 更新對象屬性到數據庫中 /// </summary> /// <param name="info">指定的對象</param> /// <returns></returns> public virtual async Task<bool> UpdateAsync(T info) { using (IDbConnection dbConnection = Connection) { return await dbConnection.UpdateAsync(info); } } /// <summary> /// 更新指定對象集合到數據庫中 /// </summary> /// <param name="list">指定的對象集合</param> /// <returns></returns> public virtual async Task<bool> UpdateAsync(IEnumerable<T> list) { using (IDbConnection dbConnection = Connection) { return await dbConnection.UpdateAsync(list); } } /// <summary> /// 從數據庫中刪除指定對象 /// </summary> /// <param name="info">指定的對象</param> /// <returns></returns> public virtual async Task<bool> DeleteAsync(T info) { using (IDbConnection dbConnection = Connection) { return await dbConnection.DeleteAsync(info); } } /// <summary> /// 從數據庫中刪除指定對象集合 /// </summary> /// <param name="list">指定的對象集合</param> /// <returns></returns> public virtual async Task<bool> DeleteAsync(IEnumerable<T> list) { using (IDbConnection dbConnection = Connection) { return await dbConnection.DeleteAsync(list); } } /// <summary> /// 根據指定對象的ID,從數據庫中刪除指定對象 /// </summary> /// <param name="id">對象的ID</param> /// <returns></returns> public virtual async Task<bool> DeleteAsync(object id) { using (IDbConnection dbConnection = Connection) { string query = string.Format("DELETE FROM {0} WHERE {1} = @id", TableName, PrimaryKey.Name); var parameters = new DynamicParameters(); parameters.Add("@id", id); return await dbConnection.ExecuteAsync(query, parameters) > 0; } } /// <summary> /// 從數據庫中刪除全部對象 /// </summary> /// <returns></returns> public virtual async Task<bool> DeleteAllAsync() { using (IDbConnection dbConnection = Connection) { return await dbConnection.DeleteAllAsync<T>(); } } }
這樣,咱們若是須要增長一個如客戶信息表的管理類,就很簡單的繼承基類就能夠了,代碼不多,可是增刪改查接口一個也少不了。
/// <summary> /// 繼承基類對象管理 /// </summary> public class CustomerDAL :BaseDAL<CustomerInfo> { }
爲了測試一下數據訪問層的處理接口,我建立了一個.net core的控制檯程序進行測試,以下項目視圖所示。
主要目的是確認數據處理的效果。
咱們在Program.cs類裏面增長相關的測試代碼,爲了簡便和處理效果沒有用UnitTest處理。
//建立管理對象,並測試接口 var customer = new CustomerDAL(); var list = customer.GetAll(); foreach (var item in list) { Console.WriteLine(item.ToJson()); var info = customer.FindByID(item.ID); Console.WriteLine(info.ToJson()); Console.WriteLine(); } //插入記錄 var insertInfo = new CustomerInfo() { Name = "test", Age = 30, Creator = "test" }; var insertList = new List<CustomerInfo>() { insertInfo }; var flag = customer.Insert(insertList); Console.WriteLine("插入操做" + (flag ? "成功" : "失敗")); Console.WriteLine("插入的新內容"); insertInfo = customer.FindByID(insertInfo.ID); Console.WriteLine(insertInfo.ToJson()); Console.WriteLine("更新內容"); insertInfo.Name = "Test" + DateTime.Now.ToShortDateString(); flag = customer.Update(insertInfo); Console.WriteLine("更新操做" + (flag ? "成功" : "失敗")); Console.WriteLine("更新的新內容"); insertInfo = customer.FindByID(insertInfo.ID); Console.WriteLine(insertInfo.ToJson()); Console.WriteLine("刪除內容"); flag = customer.Delete(insertInfo.ID); Console.WriteLine("刪除操做" + (flag ? "成功" : "失敗")); Console.WriteLine("全部內容"); list = customer.GetAll(); foreach (var item in list) { Console.WriteLine(item.ToJson()); Console.WriteLine(); } Console.ReadLine();
測試Mysql、SQLite數據庫一樣沒有問題
Mysql配置信息以下
處理的Mysql記錄信息以下。
SQLite配置信息以下
處理SQLite數據信息以下
而在處理PostgreSQL的信息(配置節點npgsql裏面)的時候,查詢的主鍵好像和大小寫有關係,致使插入記錄出錯。
而Oracle我採用的是Oracle.ManagedDataAccess.Core進行訪問,因爲我本地Oracle數據庫偵聽處理有點問題,所以沒有測試成功,暫不予置評。
而對於數據庫的支持問題,致使我從新審覈一下是否採用Dapper.Contrib仍是其餘Dapper方式來構建數據庫訪問基類的問題,我須要兼容多種數據庫的信息,而且可以儘量的封裝常規的增刪改查等操做,其中目前的基類尚未加入更加複雜的查詢操做,分頁操做等功能,在解決這些困惑問題,纔會繼續考慮把底層支持的接口所有完善。