C#教程之自己動手寫映射第五節[封裝添加]


朋友炒股兩個月賺了10萬,我幫他推廣一下公眾號,把錢用來投資總比放銀行連通貨膨脹都跑不過里強硬核離職,在家炒股 ,這是他每天的日志,有些經驗是花錢也買不到的。

一、動機

  我們通常在做項目的時候一般用到的三層結構依賴關系如下:

orm

  實體作為數據的載體,傳輸於各個組件之間。當實體到達數據操作層時,我們會把他承載的具體數據解析出來,然后利用SqlHelper.cs[也存放在數據操作層的組件中]把數據插入到數據庫中,具體代碼如下:

 1 /*
 2  *
 3  * 創建人:李林峰
 4  * 
 5  * 時  間:2012-08-01
 6  *
 7  * 描  述:員工類
 8  *
 9  */
10 
11 using System;
12 using System.Data;
13 
14 namespace CSharp.DAL
15 {
16     public class A
17     {
18         public static void Add(Model.Employee employee)
19         {
20             string strSQL = string.Format(@"INSERT INTO [A]([Name],[Password],[Department],[Position]) VALUES('{0}' ,'{1}','{2}' ,'{3}')", employee.Name, employee.Password, employee.Department, employee.Position);
21             SqlHelper.ExecuteNonQuery(Constant.CONNSTRING, CommandType.Text, strSQL);
22         }
23     }
24     public class B
25     {
26         public static void Add(Model.Employee employee)
27         {
28             string strSQL = string.Format(@"INSERT INTO [B]([Name],[Password],[Department]) VALUES('{0}' ,'{1}','{2}' ,'{3}')", employee.Name, employee.Password, employee.Department,);
29             SqlHelper.ExecuteNonQuery(Constant.CONNSTRING, CommandType.Text, strSQL);
30         }
31     }
32     public class C
33     {
34         public static void Add(Model.Employee employee)
35         {
36             string strSQL = string.Format(@"INSERT INTO [C]([Name],[Password]) VALUES('{0}' ,'{1}','{2}')", employee.Name, employee.Password);
37             SqlHelper.ExecuteNonQuery(Constant.CONNSTRING, CommandType.Text, strSQL);
38         }
39     }
40 }

   如上所示,我們在每個類里如果要實現“添加”操作,都會有一個方法,並且方法體內重復着寫着INSERT INTO.....,為了減少我們的工作量,我們對上面的代碼進行這樣的理解:

1  public static void Add("變化的實體")
2  {
3       string strSQL = string.Format(@"INSERT INTO "變化的列") VALUES("變化的值");
4       SqlHelper.ExecuteNonQuery(Constant.CONNSTRING, CommandType.Text, strSQL);
5   }

二、構想
  既然重復的代碼這么多,我們能不能把"添加"封裝成一個方法呢?想像中的偽代碼如下:

1  public static bool Add(object "對象")
2 {
3         //搞定添加......
4         //返回結果......
5 }

三、實現
  我們要實現對"添加"方法的封裝以便能夠重用,首先我們要改一下我們使用中各個組的依賴關系,把Add方法與SqlHelper類從DAL組件中分離出來放到新的組件中接口類型為object,徹底去除與"具體類型"的依賴關系。修改后的組件圖如下:

  各組件依賴關系依舊,只不過多加了個組件DBUtility。代碼如下:

 1 /*
 2  *
 3  * 創建人:李林峰
 4  * 
 5  * 時  間:2012-08-01
 6  * 
 7  * 描  述:員工數據操作層
 8  *
 9  */
10 
11 using System;
12 using System.Data;
13 using CSharp.DBUtility;
14 
15 namespace CSharp.DAL
16 {
17     public class A
18     {
19         public static bool Add(Model.A a)
20         {
21             return ORM.Add(a);
22         }
23     }
24     public class B
25     {
26         public static bool Add(Model.B b)
27         {
28             return ORM.Add(b);
29         }
30     }
31     public class C
32     {
33         public static bool Add(Model.C c)
34         {
35             return ORM.Add(c);
36         }
37     }
38 }
39 
40 
41 /*
42  *
43  * 創建人:李林峰
44  * 
45  * 時  間:2012-08-01
46  * 
47  * 描  述:orm中封裝后的添加方法
48  *
49  */
50 
51 namespace CSharp.DBUtility
52 {
53     public class ORM
54     {
55         public static bool Add(object Model)
56         {
57             //搞定添加......
58             return true;
59         }
60     }
61 }

  如上所示,要實現我們的思想,所有的添加操作都必須在"搞定添加......"中實現。

  引入實體與數據庫的映射關系的概念:在Add方法中我們傳入的是"帶有數據的具體類型的對象",而我們要實現的add(object)這個實體的數據就應該存儲到數據庫中了,是具體的數據庫插入操作,也就是說我們得到了數據,但不知道往哪個表里插入數據和這些數據應該插入到哪些字段中。這時候我們可以有一種新的想法"新建立一個依賴"對我們需要的信息進行描述以輔助我們完成該功能,如下所圖所示:

 

  我們再回頭看看插入時的SQL語句:

1 INSERT INTO tableName (Column1,Column2....) VALUES (value1,value2....)

  通過引入實體與數據庫的映射關系,我們得到了得到了插入時拼接SQL的所有信息,(1)tableName 存在於Mapping中。(2)Column存在於Mapping中。(3)value存在於傳入的object對象的屬性中。(4)具體哪個實體屬性的值應該插入到哪個字段存在於Mapping中,如:Password屬性值應該存入varPassword字段中。

  注入映射關系:即然我們的底層DBUtility要應用到這種關系,那么我們必然要把這種關系動態的注入到我們的組件中,這里我提出兩種思路:

  1. 我們可以修改Add的對外接口為Add(object model,object mapping),[此時mapping可以是類文件,但不限於類文件,大多數情況下是xml文件,也可以是是文本文件,只要我們能夠得到這種關系就可以]。
  2. 可以依賴一定的文件命名規則,如:實體類的名稱為Employee,存儲着么的映射類的名稱就必須為EmployeeMapping,在實現的內部我們用反射來得到EmployeeMapping類的實例,並調用其屬性或方法得到關系。這樣我們就不用像上面一樣每次都加上mapping這個參數了。

  萬事俱備只吹東風:前面墨跡了那么多,也不知道能讓別人看明白不,反正我是明白了,哈哈,現在寫寫實現吧,有代碼有真相。

orm

  項目結構如上所示:在DAL里有4個類,Constant是獲取Web.config的類,Employee與SqlHelper是我們最初寫三層的寫法示例,EmployeeORM是我們封裝了底層后的新寫法,DBUtility是我們新建立的組件,組件的對外接口為ORM類,其他類為輔助類。由於代比較多,這里只貼出DAL中的EmployeeORM類代碼與ORM類的代碼,其他的實現請自己下載調試吧。

 1 /*
 2  *
 3  * 創建人:李林峰
 4  * 
 5  * 時  間:2012-08-01
 6  * 
 7  * 描  述:員工數據操作層
 8  *
 9  */
10 
11 using System;
12 using System.Data;
13 using CSharp.DBUtility;
14 
15 namespace CSharp.DAL
16 {
17     public class EmployeeORM
18     {
19         public static bool Add(Model.Employee employee)
20         {
21             return ORM.Add(employee, Constant.ASSEMBLYPATH, Constant.CONNSTRING);
22         }
23     }
24 }
25 
26 
27 
28 /*
29  *
30  * 創建人:李林峰
31  * 
32  * 時  間:2010-08-01
33  *
34  * 描  述:對象關系映射類
35  *
36  */
37 
38 using System;
39 using System.Collections.Generic;
40 using System.Reflection;
41 
42 namespace CSharp.DBUtility
43 {
44     public class ORM
45     {
46         /// <summary>
47         /// 添加一個實體
48         /// </summary>
49         /// <param name="classObject"></param>
50         /// <returns></returns>
51         public static bool Add(object classObject, string AssemblyName, string ConnString)
52         {
53             int intMaxID = 0, intFlag = 0;
54             return Add(classObject, out intMaxID, intFlag, AssemblyName, ConnString);
55         }
56 
57         /// <summary>
58         /// 添加一個實體並且返回其ID標識
59         /// </summary>
60         /// <param name="classObject"></param>
61         /// <param name="intMaxID"></param>
62         /// <returns></returns>
63         public static bool Add(object classObject, out int intMaxID, string AssemblyName, string ConnString)
64         {
65             intMaxID = 0;
66             int intFlag = 1;
67             return Add(classObject, out intMaxID, intFlag, AssemblyName, ConnString);
68         }
69 
70         /// <summary>
71         /// 添加實體並判斷是否返回最大的編號
72         /// </summary>
73         /// <param name="classObject"></param>
74         /// <param name="intMaxID"></param>
75         /// <param name="intFlag">當intFlag=0時,則不去取intMaxID,等於1則相反</param>
76         /// <returns></returns>
77         private static bool Add(object classObject, out int intMaxID, int intFlag, string AssemblyName, string ConnString)
78         {
79             //聲名輸出參數
80             intMaxID = 0;
81 
82             //獲取表名稱
83             string strTableName = Mapping.GetTableName(classObject, AssemblyName);
84             //獲取主鍵字典
85             Dictionary<string, string> IdentityMapping = Mapping.GetIdentityMapping(classObject, AssemblyName);
86             //獲取除主鍵以外的字段字典
87             Dictionary<string, string> BaseFieldMapping = Mapping.GetBaseFieldMapping(classObject, AssemblyName);
88             //獲取 "屬性--值" 字典
89             Dictionary<string, string> FieldValueMapping = Model.GetValueMapping(classObject, BaseFieldMapping);
90 
91             //創建SQL語句
92             string strSQL = SQL.CreateInsert(classObject, strTableName, IdentityMapping, BaseFieldMapping, FieldValueMapping, intFlag);
93 
94             //執行SQL
95             return SQL.ExecInsert(strSQL, out intMaxID, intFlag, ConnString);
96         }
97     }
98 }

四、總結

  這節內容引入了對象與數據庫的映射的思想,這個思想在很多框架中都有應用,我們在平時開發過程中,不光要懂得怎么調用API實現功能,同時了解開發者的意圖也是非常必要的,當你理解后你會發現,我們在"思想上還是很有潛力滴"。

五、源碼下載
  06CSharp映射教程_05.rar

六、版權

  轉載請注明出處:http://www.cnblogs.com/iamlilinfeng

七、工作類了,樂喝樂喝

  今天8月1號,上午一同事果斷發圖,老着笑了。。。

orm

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM