GPS平臺、網站建設、軟件開發、系統運維,找森大網絡科技!
http://cnsendnet.taobao.com
來自森大科技官方博客
http://www.cnsendblog.com/index.php/?p=495php
經過前面兩章的描述,我相信不少朋友都已經明白我了下面將要討論到的ORM的實現方法了,那就是根據自定義Attribute來定義O/R Mapping規則,而後經過反射來動態獲取此規則,動態構造SQL語句。
因爲這個小東西(ORM)出生在深圳,因此我想來想去,她應該有個深圳的名字,因此我就叫她「MiniORM」。不知道各位認爲如何?
MiniORM採用的是ONE_INHERIT_TREE_ONE_CLASS(一個繼承樹對應於一個表)的結構,雖然這種結構容易致使數據冗餘,可是這種結構很簡單。另,本MiniORM 僅僅考慮一個表一個PK,一個FK的狀況。數據庫
MiniORM結構以下,爲了更便於理解和使用,我使用了3個類:
一、OrmWriter:負責將實體對象(好比前面章節說的Person)插入數據庫和修改數據庫中對應的記錄。
二、OrmRemover:負責根據實體對象,刪除指定的記錄;
三、OrmReader:負責根據實體對象,讀取指定的記錄;服務器
上面就是MiniORM的3個主要類。下面咱們就詳細地根據前面的描述一步步構造她。咱們這裏仍是之前面說的Person爲例進行說明。網絡
經過本系列第一章,咱們知道,對象不但存在繼承關係,特別在實際的應用中還存在包含關係,好比一個Person包含兩個Hand(手)類,包含一個Head(頭)類等,咱們的Person在數據庫中應該有一個ID,爲了更加方便使用和討論,此ID在MiniORM中是一個int以及自動增加類型(ID INDENTITY(1,1))。這些都是咱們的MiniORM應該考慮的範圍。
咱們對咱們的Person作修改:app
- [DataObjectAttribute("Person")]
- public class Person
- {
- private int _ID;
- private string _Name;
- private int _Age;
- private string _Sex;
- private Head _Head;
- private Hand _LeftHand;
- private Hand _RightHand;
-
- public int ID
- {
- get { return _ID; }
- set { _ID = value; }
- }
-
- public Head Head
- {
- get { return _Head; }
- set { _Head = value; }
- }
-
- public Hand LeftHand
- {
- get { return _LeftHand; }
- set { _LeftHand = value; }
- }
-
- public Hand RightHand
- {
- get { return _RightHand; }
- set { _RightHand = value; }
- }
-
- [DataFieldAttribute("name", "NvarChar")]
- public string Name
- {
- get { return this._Name; }
- set { this._Name = value; }
- }
-
- [DataFieldAttribute("age", "int")]
- public int Age
- {
- get { return this._Age; }
- set { this._Age = value; }
- }
-
- [DataFieldAttribute("sex", "NvarChar")]
- public string Sex
- {
- get { return this._Sex; }
- set { this._Sex = value; }
- }
- }
你可能又發現了一個問題,就是在咱們修改後的Person中,增長了LeftHand,RightHand以及Head,但是這三個都屬於類啊,這個怎麼可以保存到數據庫中呢?而且使用咱們前面的DataFieldAttribute是沒有辦法描述的啊。另外還增長了個ID,又怎麼來標誌這個是自動增加的int型PK呢?固然了可以到這裏你就發現這些問題那是至關的不錯了。若是前面就動手的人,估計考慮的仍是修改咱們的DataFieldAttribute讓它可以對這些東西進行區別。好比在DataFieldAttribute中再增長一個屬性用於區別哪一個是ID屬性,哪一個是對象類型(好比Hand)屬性。這固然是好的,只不過這樣作致使咱們的代碼極其醜陋。最好的辦法仍是另外增長一個Attribute。固然了,我是爲了更加方便的構造SQL語句,我作的不是很好。
一、怎麼表示實體類對應的數據庫表的PK和FK?
爲了更方便的實現,MiniORM中標誌一個實體類的PK和FK都是在DataObjectAttribute中來作(其實最好的辦法仍是另外增長個好比PKAttribute和FKAttribute,不過這個留給其它人去作吧)。以下,DataObjectAttribute第一個參數表示對應的數據庫表,第二個參數表示PK,第三個參數表示FK:框架
- [DataObjectAttribute("Person", "ID", "")]
- public class Person
- {
- ......
- }
二、怎麼標誌字段是Indentity(自動增加)?
在DataFieldAttribute中增長了個屬性,用於標誌某個字段是否自動增加的字段。這些都是我我的懶作的,其中,第二個參數標誌ID是Identity類型運維
- [DataFieldAttribute("ID", true)]
- public int ID
- {
- get { return _ID; }
- set { _ID = value; }
- }
三、怎樣標誌字段是類對象(好比Person中的Hand,固然複雜點的對象,可能包含子對象列表)?
因爲MiniORM提供的是一個相似框架的東西,因此不該該受到實體類的限制,因此對於類對象字段,咱們應該可以描述此對象所在的程序集,命名空間,類名,這樣咱們才能夠運行時建立該對象。工具
- public class SubDataObjectAttribute : Attribute
- {
- private SubDataObjectFieldType _FieldType;
- private string _AssemblyName;
- private string _NamespaceName;
- private string _ClassName;
-
- public SubDataObjectAttribute(SubDataObjectFieldType fieldtype, string assemblyname, string namespacename, string classname)
- {
- this._FieldType = fieldtype;
- this._AssemblyName = assemblyname;
- this._NamespaceName = namespacename;
- this._ClassName = classname;
- }
-
- /// <summary>
- /// 本記錄對應的FieldType
- /// </summary>
- public SubDataObjectFieldType FieldType
- {
- get { return _FieldType; }
- }
-
- /// <summary>
- /// 本記錄對應的AssemblyName
- /// </summary>
- public string AssemblyName
- {
- get { return _AssemblyName; }
- }
-
- /// <summary>
- /// 本記錄對應的NamespaceName
- /// </summary>
- public string NamespaceName
- {
- get { return _NamespaceName; }
- }
-
- /// <summary>
- /// 本記錄對應的ClassName
- /// </summary>
- public string ClassName
- {
- get { return _ClassName; }
- }
- }
其中SubDataObjectFieldType是一個枚舉類型,由於咱們的子對象多是單獨的對象好比Person.Head也多是一個列表(List)。因此我增長了這個枚舉類型,用於作標誌。性能
- public enum SubDataObjectFieldType
- {
- Object,
- /// <summary>
- /// 本字段屬於List類型,直接遍歷
- /// </summary>
- List,
- }
固然了,這裏的子對象列表多是ArrayList,HashTable等等,你均可以根據本身項目中實際使用到的類型來作相應的修改。網站
四、怎麼控制某個字段在表中不能重複?
好比咱們要控制Person.Name不能重複,若是你新增的時候發現重複要提示。那咱們也經過增長一個Attribute的形式來實現。這個Attribute很簡單,沒有任何方法和屬性。
- public class DataFieldNotDoubleAttribute : Attribute
- {
- }
五、怎樣作事務處理?
事務處理是每一個底層框架都應該考慮到的問題,在.NET中咱們有兩種方式來進行事務處理,一種是使用COM+,這是最好的方法,不過性能上比較欠缺,另外這東西配置很麻煩,當你數據庫安裝在另一太服務器上的時候,每每出現沒法使用的問題,我曾經就被這東西折騰夠嗆,因此我乾脆就不用他了,不過仍是介紹下語法,經過使用TransactionScope就能夠很好的使用com+提供的事務處理,代碼至關的簡潔,優美,只惋惜啊!天使的面孔,魔鬼的心。
- public void function1()
- {
- using (System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required))
- {
- function2();
- }
- }
-
- public void function2()
- {
- using (System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required))
- {
- //DoSomething();
- }
- }
另一種方法就是使用SqlTransaction:
- using (SqlConnection conn = new SqlConnection(ConnectionStr))
- {
- conn.Open();
- SqlTransaction trans = conn.BeginTransaction();
- //DoSomething();
- trans.Commit();
- }
不過遺憾的是這種方式不能實現事務嵌套,因此只能經過將trans做爲參數進行傳遞來實現事務處理。
通過上面一系列的修改後,咱們的Person成了什麼樣子了?
- [DataObjectAttribute("Person", "ID", "")]
- public class Person
- {
- private int _ID;
- private string _Name;
- private int _Age;
- private string _Sex;
- private Head _Head;
- private Hand _LeftHand;
- private Hand _RightHand;
-
- [DataFieldAttribute("ID", true)]
- public int ID
- {
- get { return _ID; }
- set { _ID = value; }
- }
-
- [SubDataObjectAttribute(SubDataObjectFieldType.Object, "Person", "Person", "Head")]
- public Head Head
- {
- get { return _Head; }
- set { _Head = value; }
- }
-
- [SubDataObjectAttribute(SubDataObjectFieldType.Object, "Person", "Person", "Hand")]
- public Hand LeftHand
- {
- get { return _LeftHand; }
- set { _LeftHand = value; }
- }
-
- [SubDataObjectAttribute(SubDataObjectFieldType.Object, "Person", "Person", "Hand")]
- public Hand RightHand
- {
- get { return _RightHand; }
- set { _RightHand = value; }
- }
-
- [DataFieldAttribute("name", "NvarChar")]
- public string Name
- {
- get { return this._Name; }
- set { this._Name = value; }
- }
-
- [DataFieldAttribute("age", "int")]
- public int Age
- {
- get { return this._Age; }
- set { this._Age = value; }
- }
-
- [DataFieldAttribute("sex", "NvarChar")]
- public string Sex
- {
- get { return this._Sex; }
- set { this._Sex = value; }
- }
- }
-
-
固然了對於Person這樣的實體類,咱們徹底能夠本身寫代碼自動生成工具來弄,而後再作很小的修改就能夠了,這樣的工具實現簡單,我就不討論了。
好了,關於個人MiniORM我就討論到這裏了,其它的請看代碼吧。
ORM雖然是好東西,可是也存在不少方面的不足,首先咱們可以作到的是將大部分的數據庫操做交個ORM來作。另外少部分仍是須要咱們本身寫SQL的。單大部分的工做的分離能夠爲咱們節約大量的時間(也就是所謂的20/80原則,80%的教給ORM來處理,20%的本身作,固然很好了)。另外經過將這些相同的流程教給ORM來處理,能夠避免不少的疏忽致使的失誤(好比不當心把某個Insert,Update,Delete語句弄錯了什麼的)。
最主要的缺點固然是性能問題,特別是個人MiniORM,所有采用反射來獲取映射規則,從而致使性能上更多的降低,不過咱們瞭解方法之後是很容易經過動態生成代碼,動態編譯的方式來減小這部分的性能損失的。另外某些部分的代碼顯得有些臃腫,特別是把判斷是否Indentity這樣的代碼放DataFieldAttribute中來處理(這個徹底能夠象DataFieldNotDoubleAttribute一分開處理的樣)等等。
GPS平臺、網站建設、軟件開發、系統運維,找森大網絡科技!
http://cnsendnet.taobao.com
來自森大科技官方博客
http://www.cnsendblog.com/index.php/?p=495