1. 程式人生 > >基於輕量級ORM框架Dapper的擴展說明

基於輕量級ORM框架Dapper的擴展說明

sca mapper server proxy mage alt .exe () 數據庫

這裏簡單的介紹一下本人基於Dapper作的一些簡單的擴展,供大家參考。

為何要使用這款框架,相信大家看到下面排名就清楚了

技術分享

其實在各大網站上,我們大概都會看到這樣的一個對比效果圖,在超過500次poco serialization的過程中所表現的性能,我們發現dapper是第二名,

當然第一名誰也無法超越,越底層的當然久越快,同時也就越麻煩。

至於如何使用進行基本的數據操作,我這裏就不再闡述,http://www.cnblogs.com/Sinte-Beuve/p/4231053.html這裏介紹了Dapper的基本使用的方法。

一.文件說明,打包的文件如下

SqlMapperExtensions類:ORM擴展類,基於SQLMapper類的擴展。

SqlMapper類--Dapper原始類:一些底層封裝代碼,使用時可查看其實現原理。
生成實體類_Dapper_模板文件:用於動態生成實體類的模板,配合DOS生成工具使用。

二.擴展類新增的幾個方法

SqlMapperExtensions類中新增: UpdateGiven()、InsertGiven()、GetPageList()方法。

UpdateGiven():更新時只更新賦值的字段

InsertGiven():插入時只插入賦值的字段

GetPageList():新增分頁查詢

另新增數據庫環境支持Oracle

三.舉栗子

這裏用上面的方法來簡單的測試一下。

 1 using
System; 2 using System.Collections.Generic; 3 using System.Data; 4 using System.Data.SqlClient; 5 using System.Linq; 6 using System.Text; 7 using System.Threading.Tasks; 8 using Dapper; 9 using System.Data.OracleClient; 10 using Dapper.Contrib.Extensions; 11 using Dapper.Contrib;
12 using Dapper.Model; 13 namespace ConsoleTest1 14 { 15 class Program 16 { 18 static IDbConnection conn = new OracleConnection("Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.79)(PORT=1521)))(CONNECT_DATA=(service_name =acid)));Persist Security Info=True;User ID=hl_platform; Password=intest;"); 19 static void Main(string[] args) 20 { 21 //創建Book表 22 conn.Execute(@" create table Book (Id number, Name nvarchar2(100) not null),Remark nvarchar2(200)"); 23 Console.WriteLine("Created database"); 24 BOOK book = new BOOK(); 25 book.NAME = "C#本質論"; 26 book.ID = 1001; 27 string query = "INSERT INTO Book(Id,Name)VALUES(@Id,@Name)"; 28 //對對象進行操作 29 conn.Execute(query, book);//原始操作 傳入sql語句和參數 30 31 ////以下是擴展中的方式 32 //直接用Insert雖然只給了部分字段,但會插入所有字段,造成數據庫的默認值會被覆蓋的情況 33 conn.Insert<BOOK>(new BOOK { ID = 1004, NAME = "Dapper" }); 34 conn.InsertGiven<BOOK>(new BOOK { ID = 1004, NAME = "Dapper" }); 35 //每次執行Update方法也是會更新所有字段,沒賦值的字段會覆蓋掉原始數據庫的值 36 conn.Update<BOOK>(new BOOK { ID = 1004, NAME = "Dapper" }); 37 conn.UpdateGiven<BOOK>(new BOOK { ID = 1004, NAME = "update Dos way" }); 38 ////以下是分頁查詢,有一個重載 39 long longCount; 40 var sortlist=new List<ISort>(); 41 sortlist.Add(new Sort{ PropertyName="id",Ascending=true}); 42 //該方法要傳入一個長整型變量供傳遞出查詢的總量 43 var pagebook = conn.GetPageList<BOOK>(0, 10, out longCount, new BOOK { ID=1004}, sortlist); 44 //該重載不需要傳入長整型變量 45 var pagebook2 = conn.GetPageList<BOOK>(0, 10, null, sortlist); 46 47 } 48 } 49 50 }

其中具體方式的實現分別如下:

技術分享
 1         /// <summary>
 2         /// Inserts an entity into table "Ts" and returns identity id.(Insert the given fields)
 3         /// </summary>
 4         /// <param name="connection">Open SqlConnection</param>
 5         /// <param name="entityToInsert">Entity to insert</param>
 6         /// <returns>Identity of inserted entity</returns>
 7         public static long InsertGiven<T>(this IDbConnection connection, T entityToInsert, IDbTransaction transaction = null, int? commandTimeout = null) where T : Entity
 8         {
 9             var type = typeof(T);
10             var name = GetTableName(type);
11             var mfields = entityToInsert.GetModifyFields();
12             if (null == mfields || mfields.Count == 0)
13                 return -1;
14             var sbColumnList = new StringBuilder(null);
15             SetSqlConnectTag(connection);//根據不同數據庫設置標記符 [email protected] Oracle:
16             var keyProperties = KeyPropertiesCache(type);
17             for (var i = 0; i < mfields.Count; i++)
18             {
19                 sbColumnList.AppendFormat("{0}", mfields[i].Field);
20                 if (i < mfields.Count - 1)
21                     sbColumnList.Append(", ");
22             }
23             var sbParameterList = new StringBuilder(null);
24             for (var i = 0; i < mfields.Count; i++)
25             {
26                 sbParameterList.AppendFormat("{0}{1}", SqlConnectTag, mfields[i].Field);
27                 if (i < mfields.Count - 1)
28                     sbParameterList.Append(", ");
29             }
30             var adapter = GetFormatter(connection);
31             return adapter.Insert(connection, transaction, commandTimeout, name, sbColumnList.ToString(),
32                 sbParameterList.ToString(), keyProperties, entityToInsert);
33         }
InsertGiven 技術分享
 1         /// <summary>
 2         /// Updates entity in table "Ts", checks if the entity is modified if the entity is tracked by the Get() extension.
 3         /// update the given fileds
 4         /// </summary>
 5         /// <typeparam name="T">Type to be updated</typeparam>
 6         /// <param name="connection">Open SqlConnection</param>
 7         /// <param name="entityToUpdate">Entity to be updated</param>
 8         /// <returns>true if updated, false if not found or not modified (tracked entities)</returns>
 9         public static bool UpdateGiven<T>(this IDbConnection connection, T entityToUpdate, IDbTransaction transaction = null, int? commandTimeout = null) where T : Entity
10         {
11             var proxy = entityToUpdate as IProxy;
12             if (proxy != null)
13             {
14                 if (!proxy.IsDirty) return false;
15             }
16 
17             var type = typeof(T);
18 
19             var keyProperties = KeyPropertiesCache(type);
20             if (!keyProperties.Any())
21                 throw new ArgumentException("Entity must have at least one [Key] property");
22 
23             var name = GetTableName(type);
24 
25             var mfields = entityToUpdate.GetModifyFields();
26             if (null == mfields || mfields.Count == 0)
27                 return false;
28             for (var i = 0; i < keyProperties.Count(); i++)
29             {//排除主鍵
30                 var property = keyProperties.ElementAt(i);
31                 if (mfields.Select(t => t.Field).Contains(property.Name))
32                     mfields.Remove(mfields.FirstOrDefault(t=>t.Field==property.Name));
33             }
34             var sb = new StringBuilder();
35             sb.AppendFormat("update {0} set ", name);
36             SetSqlConnectTag(connection);//根據不同數據庫設置標記符 [email protected] Oracle:
37             for (var i = 0; i < mfields.Count; i++)
38             {
39                 sb.AppendFormat("{0} = {2}{1}", mfields[i].Field, mfields[i].Field, SqlConnectTag);
40                 if (i < mfields.Count - 1)
41                     sb.AppendFormat(", ");
42             }
43             sb.Append(" where ");
44             for (var i = 0; i < keyProperties.Count(); i++)
45             {
46                 var property = keyProperties.ElementAt(i);
47                 sb.AppendFormat("{0} = {2}{1}", property.Name, property.Name, SqlConnectTag);
48                 if (i < keyProperties.Count() - 1)
49                     sb.AppendFormat(" and ");
50             }
51             var updated = connection.Execute(sb.ToString(), entityToUpdate, commandTimeout: commandTimeout, transaction: transaction);
52             return updated > 0;
53         }
UpdateGiven
 1  /// <summary>
 2         /// Paging
 3         /// </summary>
 4         /// <typeparam name="T">傳入實體類型</typeparam>
 5         /// <param name="connection">此連接</param>
 6         /// <param name="pageIndex">第幾頁:0為第一頁開始</param>
 7         /// <param name="pageSize">每頁數量</param>
 8         /// <param name="allRowsCount">返回滿足條件總量</param>
 9         /// <param name="entityToPredicate">條件:實體傳入</param>
10         /// <param name="sort">排序條件:ISort列表方式傳入</param>
11         /// <param name="buffered">是否緩存</param>
12         /// <returns></returns>
13         public static IEnumerable<T> GetPageList<T>(this IDbConnection connection, int pageIndex, int pageSize, out long allRowsCount,
14         T entityToPredicate = null, IList<ISort> sort = null, bool buffered = true) where T : Entity
15         {
16             DynamicParameters dynamicParameters = new DynamicParameters();
17             var type = typeof(T);
18             SetSqlConnectTag(connection);//根據不同數據庫設置標記符 [email protected] Oracle:
19             var keys = KeyPropertiesCache(type);
20             if (keys.Count() > 1)
21                 throw new DataException("Get<T> only supports an entity with a single [Key] property");
22             if (!keys.Any())
23                 throw new DataException("Get<T> only supports en entity with a [Key] property");
24 
25             var onlyKey = keys.First();
26             StringBuilder innersql = new StringBuilder(string.Format("SELECT * FROM {0}",
27                 GetTableName(type)));
28             if (entityToPredicate != null)
29             {
30                 var mfields = entityToPredicate.GetModifyFields();
31                 innersql.Append(" where ");
32                 for (var i = 0; i < mfields.Count; i++)
33                 {
34                     innersql.AppendFormat("{0} = {2}{1}", mfields[i].Field, mfields[i].Field, SqlConnectTag);
35                     if (i < mfields.Count - 1)
36                         innersql.AppendFormat(", ");
37                     dynamicParameters.Add(mfields[i].Field, mfields[i].NewValue);
38                 }
39             }
40             if (sort != null && sort.Any())
41             {
42                 innersql.Append(" ORDER BY ")
43                     .Append(sort.Select(s => s.PropertyName + (s.Ascending ? " ASC" : " DESC")).AppendStrings());
44             }
45             allRowsCount = connection.Query(innersql.ToString(), entityToPredicate).Count();
46             Dictionary<string, object> parameters = new Dictionary<string, object>();
47             string sql = GetFormatter(connection).GetPagingSql(innersql.ToString(), pageIndex, pageSize, parameters);
48             foreach (var parameter in parameters)
49             {
50                 dynamicParameters.Add(parameter.Key, parameter.Value);
51             }
52             return connection.Query<T>(sql, dynamicParameters);
53         }

下面我們來調試一下來看看Insert和InsertGiven、Update和UpdateGiven的區別吧

1  ////以下是擴展中的方式
2   //直接用Insert雖然只給了部分字段,但會插入所有字段,造成數據庫的默認值會被覆蓋的情況
3   conn.Insert<BOOK>(new BOOK { ID = 1004, NAME = "Dapper" });
4   conn.InsertGiven<BOOK>(new BOOK { ID = 1004, NAME = "Dapper" });
5   //每次執行Update方法也是會更新所有字段,沒賦值的字段會覆蓋掉原始數據庫的值
6   conn.Update<BOOK>(new BOOK { ID = 1004, NAME = "Dapper" });
7   conn.UpdateGiven<BOOK>(new BOOK { ID = 1004, NAME = "update Dos way" });

Insert生成的sql語句:

技術分享

InsertGiven生成的sql語句:

技術分享

Update生成的sql語句:

技術分享

UpdateGiven生成的sql語句:

技術分享

想必擴展的方法個中緣由就一清二楚了。

四.實體類生成

其中BOOK實體類如何生成?這裏借鑒了DOS生成實體類工具,並新增了一個模板文件->生成實體類_Dapper_模板文件.tpl

打開DOSTOOL的Debug文件,將其放入模板文件中,重新打開DOSTOOL文件便可看見新增了一個模板,選擇其模板,生成代碼即可。

技術分享

技術分享

技術分享

以上。

基於輕量級ORM框架Dapper的擴展說明