天天看點

吉特倉庫管理系統-ORM架構的使用

  一. 為什麼會有這個架構

    當年沒有Linq to SQL , EF 等ORM架構的時候, 寫SQL也還是相當痛苦的一件事,市面上當時有MyBatis架構, 這個ORM是從java移植過來的,好不好用不過多的說, 褒貶不一。但是我個人用下來就是有一個很不爽的就是那個配置SQL,那個SQL的配置檔案超級特麼的多,多到節操都快碎了一地。後面上班公司又基于微軟企業庫做了一個類似的ORM架構, 這個也沒有改變其配置檔案的蛋疼本質,那個誰一怒為紅顔,我特麼的一怒差點撂挑子不幹了。痛定思痛我決定自己來改改這個狗日的配置檔案,最終有所成也就成了現在吉特倉儲系統中使用的Git.Framework.ORM 架構。

    之前也相關自己要做一款非常不錯的ORM元件,要支援MS SQL,MySQL,Oracle,Sqlce,Sqlite 等,不過也是真的嘗試過,不過我還是有點異想天開,後面做到了對SQL Server,MySQL,Oracle的支援, 終究覺得做的不是那麼好,是以也就堅持不下去了,做出來終究也是就是跟别人裝逼,後面放棄了對多資料庫的支援,隻對SQL Server 進行了重點的支援(可能是我能力有限以及對整體結構規劃的缺失,導緻對其他的資料庫支援性并不是那麼好),因為我隻是自己用而且我的最終目的不是做一個ORM,而是針對某種業務型的項目來輔助支撐。

  二. ORM中資料庫腳本配置問題

吉特倉庫管理系統-ORM架構的使用
吉特倉庫管理系統-ORM架構的使用

資料庫腳本配置問題

  最初系統中所有的SQL語句都是通過以上方式來配置配置在配置檔案中,寫了一個比較牛逼的DataCommandManager類用于來解析讀取這些SQL, 這些配置都是緩存的。并且直接轉化為了ADO.NET中的Command對象,隻需要在使用的時候連接配接資料庫并且傳入參數執行就可以,這樣看起來并不錯。說好話這樣是挺爽的,SQL 不用寫死在C#代碼中了,可以随時在配置檔案中修改, 這是java中一直流傳的套路(不懂java,但是看到的現象是這樣的),項目越做越龐大問題就來了, 業務越來越複雜SQL越來越多,配置檔案多到沒法維護了,一個問題調試都不知道從何處還是找起,即使在配置檔案命名規範上死下功夫仍然存在大量的問題,比如配置檔案name值是一樣的重複了,SQL寫重複了也沒辦法知道,除非你知道這個項目裡面的所有配置節點。

  這個配置節點中的name 是配置資料庫SQL的唯一鍵值, SQL的配置檔案多達上百個,這個name重複了有時候根本不知道從何處找起,也想過使用工具來查找,但是這樣終究是效率不高的。難道我每次寫一個SQL都要查找一下name是否存在,當然很多人也會說無所謂嘛,但是我個人覺得這個不應該是工作的重點,更加應該将重心放到業務上去。

  三. ORM 配置重複的SQL

吉特倉庫管理系統-ORM架構的使用
吉特倉庫管理系統-ORM架構的使用

配置重複的SQL

  上面這個這兩個SQL一模一樣,隻是name的值不一樣,當時多人開發導緻你根本無法知道這個SQL是不是重複了,雖然這個對程式運作沒有什麼影響,但是終究是重複了。而且我幾乎不可能判斷SQL是不是有重複的。這個就存在一個相當坑爹的事情,要做這個事情還是要花費一點時間,但是沒有辦法公用,不說每個開發人員都會搞一套,但是這種重複的問題是的的确确存在的問題,我相信做MyBatis開發的肯定深有體會。

吉特倉庫管理系統-ORM架構的使用
吉特倉庫管理系統-ORM架構的使用

操作配置檔案中的SQL語句

  以上是操作配置檔案中C#代碼,其實也就比Ado.NET 友善那麼一點點,如果加上配置等操作完全不會比Ado.NET簡單。上面這種還是個别案例,上面這段SQL用的人估計不會很多,如果涉及到業務問題比如擷取某個使用者的資訊,這個時候技術人員溝通不暢那麼就極有可能出現重複的代碼。再後來的接盤俠過來了怎麼辦,我該怎麼擷取使用者的資訊,寫了這麼多擷取使用者的資訊,以前的又不敢動那我再重新寫一個吧。

  四. ORM擷取使用者資訊

吉特倉庫管理系統-ORM架構的使用
吉特倉庫管理系統-ORM架構的使用

我要擷取使用者資訊?

  擷取使用者資訊偷懶的辦法,我們在查詢字段的時候直接SELECT * FROM , * 通配符真是一個好東西,可以少些好多的代碼,用起來就是爽。如果從業務和更加嚴謹的角度來說其實我們不建議使用 * 來查詢所有表字段資訊。業務環境點要求:我要查詢使用者編号和使用者名,我要查詢使用者名,使用者編号,使用者郵箱,我要查詢使用者所有的屬性資料,我要查詢使用者..... ;  這種需求再正常不過了,假設我們不允許在所有環境下查詢所有的資料庫屬性字段,根據上面的架構來開發的話,那的配置多少個SQL配置節點,我要寫多少個DataCommand,這還隻是其中一個業務點,一個系統怎麼可能隻有一個業務點。

  五. 資料字段權限如何處理

吉特倉庫管理系統-ORM架構的使用
吉特倉庫管理系統-ORM架構的使用

擷取所有使用者資料

吉特倉庫管理系統-ORM架構的使用
吉特倉庫管理系統-ORM架構的使用

查詢使用者編号和使用者名

吉特倉庫管理系統-ORM架構的使用
吉特倉庫管理系統-ORM架構的使用

查詢使用者身份資訊

  在業務系統中有些是特别敏感的資訊,比如ERP系統中對價格控制,客戶能夠看到什麼價格,VIP看到什麼樣的價格,什麼級别的上司看到又是另外的價格,人就是這麼的坑爹! 我相信這是一個再普通不過的業務場景了,各種價格保持到不同的資料庫列中,很多人的做法就是先将資料查詢出來,然後在用代碼将沒有權限的資料隐藏掉,這個也是我個人的一般做法,那麼我們能不能在讀取資料的時候就控制呢,根據權限查詢特定的字段資訊。這個肯定不用多說肯定是可以的, 根據上面的這種ORM配置來做 就是上面三種類型的配置,好坑爹啊。

======================ORM就是一個坑爹貨啊,根本達不到快速開發效果===========================

 六.徹底一些 ORM

    以上的事情足夠蛋疼好久的,每天要花大量的體力勞動時間來配置這些SQL語句,我能不能在不改動原有的結構基礎上讓這些操作變得更加的簡單一些。這是得讓我們好好想想的事情,ORM架構的核心點在哪裡,那就是解決對象與資料庫之間的映射關系以及對象與對象之間的關聯關系。先不說DataCommand這個類,我們分析Ado.NET 操作資料庫的特點,幾個步驟就不說了。兩個核心點:(1) SQL語句并且帶有占位符(可選) (2) 設定占位符參數 , 仔細想想這兩個是有規律的,最起碼第二個規律很明顯,就是AddParamater() 我們完全可以使用參數的形式循環設定這些占位符參數。

    SQL語句的規則稍微有點複雜:

    (1) 增: insert into table (字段,字段) values(值,值)

    (2) 删: delete from table where 條件  

    (3) 改: update table set 字段=值,字段=值 where 條件

    (4) 查: select *(字段) from table where 條件

    解決以上ORM的問題,那麼就是如何動态的去替換如上語句的關鍵字。 這裡動态很重要,我們需要動态的去設定動态列以及條件,避免寫死的去配置SQL語句,動态也就意味着不同的條件生成的SQL是不一樣的,不需要配置檔案窮舉這些SQL語句了。我想ORM架構的開發基本就是這個理吧,隻要具體細節如何實作就看對文法的了解以及對架構的設計如何了。

  七. 先說映射的屬性

吉特倉庫管理系統-ORM架構的使用
吉特倉庫管理系統-ORM架構的使用

映射的實體對象

  ColumnName是映射的列與屬性之間的關系,這個是核心也是關鍵,還有一個就是IsMap 這個屬性 這個表示是否映射字段。為了靈活性我當然可以擴充這個實體類,但是我就是不想和資料庫字段建立關系,你想怎樣。 

  一個實體對象映射一張表, 代碼中我可以擴充這個實體對象屬性,這些屬性是和表之間唯一對應的,但是我是可以在查詢的時候連接配接查詢字段或者計算出來的字段做映射關系的,我就說了查詢是SQL中最難的。增删改在操作的時候都必須和對應的表字段對應,而查詢偏偏不是這樣的,我查詢可以從其他表關聯查詢出來,我可以取别名,我可以查詢自定義新的列, 對象是否處理,那關鍵就是看IsMap 這個值了。

  實體上有DataMapping 特性辨別,說明和資料有映射關系,如果沒有則和資料庫映射操作沒有關系,資料庫無論怎麼操作都不影響這些資料。 辨別IsMap=true的屬性 這個是和資料庫字段強制關聯的(一般用于增删改), 沒有這個值預設是false,這個時候查詢也會映射到此類屬性上.

  八. 定義了一套文法規則

吉特倉庫管理系統-ORM架構的使用
吉特倉庫管理系統-ORM架構的使用

資料庫表操作接口

吉特倉庫管理系統-ORM架構的使用
吉特倉庫管理系統-ORM架構的使用

資料庫表操作實作

  傳說中的DbHelper, 之前還有人專門寫過一篇關于DbHelper的文章,到底要不要叫DbHelper, 我不想談論此類文章,畢竟我不是搞技術研究的料。此DbHelper 并非傳統的DbHelper類,這個是自己改良過的(并非改良,是完全不一樣,隻是名字相同而已), 深受DDD領域驅動設計的毒害,每個人都這麼搞我也就弄了一個似于上面的倉儲模式,我水準低你們不要笑話我,我也不知道這個DDD中的倉儲是不是正宗的,隻是看起來有點像,我此等超低領悟能力的人有點了解不來。因為我看到網上的.NET 相關的文章 DDD倉儲模型都是使用EF實作的,千篇一律沒有其他之一。

  在系統中我同樣會定義很多類似于上面的空的接口和空的實作實作類,基本每個表回對應一個這種模型,如果表很多該怎麼辦,你懂得, 做程式的雖然不聰明但是也絕對不會傻逼到每個都手寫。

吉特倉庫管理系統-ORM架構的使用
吉特倉庫管理系統-ORM架構的使用

新增一個實體對象

  在實體新增的時候,會将資料保持到實體對應的表中去,其中可能大家比較關注的是哪個IncludeAll() , 這個就是解決上面的指定指定問題的, IncludeAll() 意味着新增的時候會生成所有的字段插入到表中。

  這段代碼表示在表中隻新增兩個字段,IncludeAll() 是新增所有的字段. 當然如果你在新增的時候資料庫設計必填而你沒有包含進去,這個時候執行SQL的時候是會報錯的。

  鍊式表達式,上面的這段代碼和表達式這段代碼是等價,在操作新增的時候都是包含了兩個字段。隻要能夠和字段映射的上,你就可以無限次的包含字段關系。

  你執行的SQL語句可以是這樣,當然你也可以這樣

  該死的窮舉配置所有的SQL可能性,可以滾蛋了。

  九. 查詢關聯的字段

    你的ORM架構支援加載子類集合麼,或者自動加載主表的資料麼。 NO NO NO, 你特麼的不要跟我提為什麼不加載字表的集合,别的架構都支援加載子類集合啊?? 好煩 好煩 這種問題。  個人縮寫的這個ORM架構的确是不支援自動加載子類集合的,第一 個人能力有限, 第二 做ORM就一定要加載子項麼, 我就單表操作不可以麼(這裡不是說隻能操作一張表,是能夠連接配接查詢的,但是連接配接查詢出來的結果集也是一張表啊)。 你别傻了, 變通 變通 變通!

吉特倉庫管理系統-ORM架構的使用
吉特倉庫管理系統-ORM架構的使用

左連接配接查詢的相關操作

    在上面的IsMap 屬性還記得麼,上面說到了他就是為了解決連接配接查詢中字段不能比對實體的問題(反正就是一個區分到底比對不比對). 這是使用這種實體模型的時候,我們要大量去擴充資料庫映射模型屬性, 有點違法了大家DDD說的資料庫模型,業務模型,資料傳輸模型等分離的原則,什麼原則我是不懂了,在有些人眼裡肯定是不倫不類了。

    這個左連接配接查詢出來的屬性字段,肯定要在實體類InventoryDetailEntity 中有對應的屬性字段了。

吉特倉庫管理系統-ORM架構的使用
吉特倉庫管理系統-ORM架構的使用

擴充屬性字段

    可以和上面的那個實體對象做一下對比,DataMapping 也辨別了,沒有那麼多屬性其實都是預設了,IsMap其實就預設了false,說明這些屬性和表Inventory 沒有直接的對應關系(記住一個宗旨,任何操作都可以看做是一個單表操作)。

  十. 如何解決上面提出的問題

    如果你還不能明白如何解決上述提出的問題,比如多配置,命名重複,權限字段等問題,那我隻能說你還沒有明白我寫的文章,要麼就是我寫的文章太不入流了,不能讓你能夠很清楚的明白我的意思。

    我本身不是想做一個ORM架構,我就是想做了一個軟體,然後逐漸的提高開發效率。其他人我不知道了,自從改進到目前的這個程度,在開發效率上的确提升很多了。自我感覺是良好的。 我深知這個ORM不能跟其他的ORM相比,看别人的ORM簡直就是高大上,我做這個ORM完全是為了解決當初的開發遇到的問題以及從自己做吉特倉儲系統業務的角度來出發的,是以在很大的程度上是有局限性的。但是我相信在整個架構體系中(包括業務的設計)是可以在很大程度上彌補Git.Framework.ORM 方面的不足。

    技術是為業務服務,是為了解決問題,如果單純的隻是為了做架構而架構,我并不覺得這是一個好的方式,就好比DDD領域驅動設計,這種設計思想是很好的,但是請别千篇一律的的找一個使用了DDD設計思想的技術架構奉為定律, 架構本身就是要靈活多變的,不同的業務體系架構也就會不一樣,架構也會不一樣。(恕我不懂DDD的精髓在此說了大話)

關于作者:從事倉庫,生産軟體方面的開發,在項目管理以及企業經營方面尋求發展之路

版權聲明:本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連結。

聯系方式: 個人QQ  821865130 ; 倉儲技術QQ群 88718955,142050808 ;