從本篇開始,本系列將進入實戰演練階段。程序員
前面主要介紹了一些應用程序框架的概念和基類,原本想把全部概念介紹完,再把框架內部實現都講完了,再進入實戰,這樣可讓初學者基礎牢靠。不過個人精力頗有限,文章進度愈來愈慢,因此準備切換一下介紹順序,把實戰演練提早,以方便你閱讀代碼。數據庫
本系列實戰演練共分兩個部分。編程
實戰演練第一部分介紹如何快速解決CRUD機械操做,這一部分我將手把手帶領各位同窗從搭建VS環境開始,建立程序集及各程序集間的依賴關係,以及引入依賴的外部DLL,並手工完成代碼示例中Application的三種界面操做。當你熟悉了手工操做方式後,你會發現這些工做枯燥乏味,效率低下,且容易出錯。爲解決該問題,我將爲你介紹PowerDesigner(PD)和CodeSmith兩大工具,分享PD及數據建模技巧,併發布配套的CodeSmith模板,你將體驗到高質量完成機械代碼的最佳實踐。架構
實戰演練第一部分介紹的內容頗有用,它將幫助你完成大量體力活,但這個示例太簡單,體現不出領域模型的威力,實戰演練第二部分以權限模塊爲例,演示如何開發具備必定業務邏輯的模塊。併發
固然,在介紹實戰演練第二部分以前,我須要先把框架內部重要代碼講解完,本系列大體構成以下:框架
不少同窗反映,閱讀個人示例代碼很是困難,通過了解,我發現大可能是閱讀方法有問題,在此給出一些建議。工具
對於別人的代碼,你閱讀起來很痛苦是正常現象,由於編程習慣和風格不一樣,另一個緣由是對代碼的意圖不瞭解。佈局
我提供了Managements和Util兩個VS解決方案,Managements是簡單管理系統的代碼示例,Util是框架代碼,它是基礎設施層的一部分,被分離出來的緣由是讓業務項目更簡單、編譯更快。學習
閱讀代碼須要從簡單的東西入手,這裏就是Managements解決方案,它裏面包含了一個叫Application的CRUD操做,它是權限系統中的應用程序模塊,具體功能先不要考慮。Application模塊是一個單表操做,很是簡單,幾乎沒有業務邏輯,很適合用來入門。EasyUi提供了三種數據錄入方式,即表單操做、表格操做、行內操做,我使用Application模塊演示了這幾種操做方式。ui
有些同窗下載代碼後,直接看的Util代碼,它主要包含一些基類和公共操做類,看起來困難就在所不免了。
爲了減小程序集數量,我把一些第三方開源框架的代碼直接放入Util解決方案中,有些同窗直接就看到這裏面去了,而後告訴我異常複雜。不要泄氣,說明你是一個正常人,對於第三方開源框架的代碼,我也懼怕,嘿嘿。個人代碼風格很容易辨認,就是每一個方法都具備中文註釋,當你發現代碼沒有註釋或註釋全是英文,那必定不是我寫的,個人英文水平很菜。
當你把Application看熟之後,能夠本身動手建立與Application相似的表,並手工完成三種CRUD操做。
當你對CRUD相關的類和配置熟悉以後,就能夠查看基類實現,這時候帶着問題去看Util代碼,會容易理解得多。
下一步就是把這些代碼逐步移植到你本身的項目中,只有把它們變成你的東西,才能發揮更大做用。這也是我寫這個系列的目的,不只授之以魚,更要授之以漁。
建議你至少可以擴展以後,才把個人東西用到你的項目上,否則坑不少,風險高。
CRUD是Create、Retrieve(Read)、Update、Delete的縮寫,中文名:增刪改查。不論哪家的應用框架,都特別關照它幾兄弟,爲何?
對於通常的中小型項目,業務邏輯複雜的模塊只佔很小的比例,一半以上的模塊都比較簡單。這些簡單模塊大體會經過一個界面或設備接口把數據收集上來,基本不通過中間處理(業務邏輯),直接存入數據庫,在有須要的時候會把這些數據展現出來,或者爲複雜模塊提供基礎支持。
這些簡單模塊工做量大,技術含量低,經過手工的方式編寫效率低下。
當採用了分層架構,特別是DDD分層架構以後,更是雪上加霜。
對於採用了DDD這種複雜分層架構,哪怕業務邏輯很複雜,仍是存在很多機械工做,主要是建立各層的構造類型,好比領域實體及屬性、DTO及屬性映射、EF映射等,這些工做是必須的,但很枯燥乏味。
能夠看到,只要是信息系統,不論簡單仍是複雜,都存在機械工做,不一樣性質的項目機械工做所佔比例不同而已。
後面我將用CRUD來指代開發中碰到的一切機械工做。
對於機械工做,最好的辦法是依靠生成器自動建立代碼,在討論生成器以前,先討論下EF相關的概念。
EF在剛出土的時候,提供一個叫實體數據模型的edmx文件,打開這個文件,發現它是一個可視化類圖設計器。
在新建edmx文件時,有「從數據庫生成」和「空模板」兩個選項。
若是你選擇「從數據庫生成」,說明你本身先建立了數據庫,再經過edmx的反向生成工具生成代碼,這就是所謂的db first,first是先行或優先的意思,db first就是數據庫先行,先建立數據庫,再讀取數據庫的元數據,生成代碼。
若是你選擇了「空模板」,你能夠在edmx可視化類圖設計器中建立一些類和關聯,edmx會自動幫你生成代碼和數據庫。這種方式稱爲model first,即模型先行,先有模型,後面再建立代碼和數據庫。
代碼生成出來後,你會發現這些代碼文件被包含在edmx文件中,包括領域實體和DbContext工做單元,還有一些T4模板,這有什麼影響?
若是採用DDD分層架構,領域實體屬於領域層,而DbContext屬於基礎設施層,放到一塊兒會致使高耦合以及分層不清,這是edmx的主要問題。另一堆不相干的代碼生成模板與領域實體放到一塊兒,估計也讓你看着心煩。
EF後續推出了更加輕量的使用方式,讓你能夠拋棄edmx文件,直接使用原生的DbContext,並支持了code first開發模式。code first即代碼先行,先寫代碼,再自動建立數據庫。code first開發模式可以真正實現持久化無關,從而設計出更加純淨的領域模型,特別在採用TDD開發時,更加威猛。
從上面能夠看出,edmx和原生DbContext是兩種不一樣的EF技術,而db first、model first、code first則是不一樣的開發模式,但這些術語很是混亂,不一樣的人說同一個術語時可能指的是不一樣的東西。
常常聽到有人說他用的是code first,但實際上他的開發方式是先建立數據庫,再生成代碼,這屬於db first,他用code first指代原生DbContext技術。
還有一些人懼怕使用EF,由於他認爲原生DbContext只能使用code first開發模式,而他想採用db first方式,但他又不喜歡edmx。
我用原生DbContext這個詞的意思是,單獨使用DbContext這個基類,由於edmx也使用的是DbContext,以示區別。
下面用一個圖來總結一下,若是說得不正確,請各位同窗批評指正。
從上面分析得知,edmx不適合DDD分層架構,因此咱們在EF技術上採用原生的DbContext,這個沒有什麼疑問了。那麼開發模式是否必定要採用code first呢?
前面說了,code first能夠得到更純的領域模型,但你見過爐火純青的領域模型長什麼樣嗎?對於DDD架構初學者,在很長時間都難領悟到它的精髓,因此不論你以code first仍是db first,其結果沒有顯著不一樣。
其次,.net大部分項目都是中小項目,且不太複雜,CRUD機械工做佔很大篇幅,使用code first手工敲代碼,效率十分低下,且工做量與表中的字段數量成正比。在配合TDD的狀況下,才能夠和生成的代碼質量媲美,不然BUG依舊。
能夠看到,雖然code first萬衆矚目,但卻只有DDD高手開發很複雜的業務才能真正發揮威力。很複雜的業務需求,可能邏輯很是複雜,僅簡單蒐集數據字段,並不能很好的完成任務,這種場景基於DDD進行行爲建模並配合TDD推動項目更有保障。
根據個人項目實際狀況,我採用了db first,第一步用PD數據建模,第二步用PD生成建庫腳本建立數據庫,第三步採用CodeSmith生成代碼,第四步選擇性的複製代碼並創建領域模型。
不少同窗一聽代碼生成器,就會問哪一種生成器最好,還有些同窗則乾脆本身開發,畢竟你們都是程序員,要開發個生成器軟件有何難。
技術人員老是對技術自己比較感興趣,容易忽略作一件事的真正目的。其實對於代碼生成器來講,真正重要的不是生成器軟件,而是你須要得到的最終代碼,它是由你的模板決定的。
要建立出一套高質量的模板,關鍵是不斷提純本身的代碼,把重複的代碼儘可能提取到基類。
對於採用哪一種生成器軟件,根據本身的熟悉程度和喜愛進行選擇,我採用的是CodeSmith。
CodeSmith是一個收費的代碼生成器,不過你們都使用綠色環保版本。使用它的緣由是功能比較強大,可以與VS進行集成,編寫模板時具備代碼提示,相似ASPX語法,學習成本低,另外官方提供了一套EF DbContext模板,咱們只須要簡單修改,就能夠用於實際開發中。
須要建立哪些部分的代碼呢?在最理想的狀況下,全部機械代碼所有生成,這樣你能夠在最短期內拿下大部分機械工做,爲你可以集中火力完成核心功能奠基基礎。
下面討論幾個與生成器相關的問題。
通常的代碼生成器都是經過讀取數據庫元數據來生成代碼。
如何評價生成的代碼質量高低?
第一個特徵,全部代碼是否具備準確的註釋。
大部分程序員都不喜歡寫註釋,不知道是由於打字慢,仍是以爲不必。哪怕你英文很牛X,你的命名很是標準,但你不能保證看你代碼的人具備一樣的英文水平。況且大部分人的英文仍是和我同樣菜,命名十分晦澀。在這種狀況下,不要說給別人留條活路,那是給本身未來留的。
若是你採用code first模式,手工編寫全部代碼,相信能給全套代碼寫全註釋的人很少,每一個領域實體的屬性頭上都要加上註釋,並且還有大量類似類,好比Dto,不復制代碼很難作到。
第二個特徵是自動幫你生成EF導航屬性及相關映射配置,這是經過讀取外鍵關係來建立的。
不少.Net程序員不知道數據建模的價值,若是你問我一個項目裏,哪一種文檔最重要,我會絕不猶豫的告訴你——數據建模文檔。
爲何數據建模這麼重要,若是你如今接手一個遺留系統,你最須要什麼?需求文檔?類圖?序列圖?需求你不懂,還能夠找用戶問,但數據庫中一個命名很晦澀的列,你要猜出它是什麼意思,則難如登天。而類圖和序列圖等UML建模,主要是前期幫助理解和設計領域模型,不必定可以與代碼同步更新,另外也不可能對每個模塊建立UML,徹底沒有必要。
經過PowerDesigner進行數據建模,你可讓系統清晰度上升幾個層次,讓你看清表之間的關係,以及每一個列的具體含義。
你能夠在數據建模時,把每一個列的註釋加上,用PD建立數據庫後,生成的代碼中就具備良好的註釋了。
當你在表之間用關聯線一拖,外鍵關係就創建了,生成的代碼就具備了導航屬性。
固然你能夠直接在數據庫中建立表,並添加註釋,並手工建立外鍵關係。但這並無讓你減輕工做量,反而工做量更大,使用數據建模,工做輕鬆高效,且對項目將來維護有深遠影響。
生成高質量代碼,除了你的模板外,另外一個影響它的就是數據建模。
我將在後面幾篇分享我整理的CodeSmith模板,對於簡單的CRUD操做,它能夠生成全套代碼,代碼質量與我手工編寫無異。
對於從三層架構過來的朋友,不少都用過代碼生成器。
若是系統有100個表,他們會把這100個表先建好,而後一次生成出來,而後再花幾小時到幾天的時間來整理修改。
這個開發效率看上去很誘人,對於比較簡單的三層架構和SQL操做多是有效的,但對於EF+DDD分層架構卻不太吃香。
對於EF的導航屬性,生成出來都是雙向導航,但爲了下降複雜度,可能會手工調整爲單向導航,這時候也須要手工修改映射代碼。
EF操做,我老是保持小步前進,前進太快,出現任何一個問題,均可能浪費更多時間。不少時候看EF異常提示很難定位到問題,甚至斷點調試也不起做用。這種狀況下,最好的辦法就是小步走,一出問題就能夠迅速解決。
用代碼生成器建立DDD分層架構,一個弊端是致使一個表對應一個聚合,每一個表都有一個倉儲,這把你又帶回了三層架構時代。不過對於新手來講,這沒有多大問題,每一個人都有一個成長的過程,第一步把充血模型用起來就好了,下一步再考慮聚合。
但對於達到必定經驗的人,直接用生成的代碼就不合適了,由於聚合是DDD分層架構的核心,聚合使用得好,能顯著下降系統複雜性,並使業務邏輯更好的內聚。
因此若是你具有必定經驗之後,不該該徹底採用代碼生成的老方式,更不能偷懶。應該選擇性的複製代碼,手工組織聚合結構,這樣一來,不少生成的代碼都不須要了,好比某個倉儲操做的是聚合內部實體,系統複雜性會大幅下降。
個人方法是,按依賴順序手工複製須要的代碼,按聚合粒度複製並組織代碼,一次操做一個聚合,把界面運行經過後再複製下一個。
這樣可讓你用db first模式開發出較高質量的領域模型,固然質量高低與水平成正比。
對於很簡單的CRUD模塊,大多都是單表結構,這種狀況下,一個表原本就是一個聚合,代碼直接COPY,你的主要工做是調整下界面。
對於比較複雜的模塊,根據本身的理解手工複製代碼組織聚合,生成的代碼通常都達不到要求,好比界面佈局比較複雜,這時候你會發現,生成的代碼主要用於填充內容,你本身完成佈局等功能。
更復雜的模塊,能夠先不生成代碼,用TDD推動並模擬出業務邏輯後,再進行數據建模生成代碼,並複製須要的文件。
對於強大一點的生成器,都可以嵌入VS,並一鍵生成。這個特性也很誘人,若是把生成器嵌入生產項目,就不須要COPY文件了,這看起來可以極大的提高開發效率。
與上一個問題同樣,當你把生成器嵌入生產項目,生成的全部文件都進入你的項目,不論你需不須要它,這致使每一個表一個倉儲,增長了複雜性。
個人方法是,把代碼生成器與生產項目分離,手工複製相關文件,雖然看上去效率低,但能夠根據須要選擇代碼和從新組織代碼,質量將高得多。
採用代碼生成器的一個問題是,每當數據庫增長一個字段,代碼上相關的位置都要同步更新,不少懶漢但願經過從新生成並全面覆蓋來解決這個問題。
個人方法是僅在第一次生成全套代碼,後面經過手工添加相關屬性,若是增長的字段比較多,我可能先生成代碼,再手工將差別屬性複製過去。緣由很簡單,項目上的代碼不是徹底生成的,有修改過的地方,從新生成並徹底替換,可能會覆蓋已修改代碼。
不少人在生成器下了大量功夫,可以支持複雜的配置,以生成出很是智能的代碼。
這可能形成對代碼生成器的高度依賴,我僅使用代碼生成器解決機械的簡單工做,對於更智能的手工完成。
個人方法是一鍵生成簡單代碼。
有人看見生成的代碼中,不少類都直接從基類派生,裏面徹底是空的,是否能夠簡化掉。
這些類中啥也沒有的緣由是,基礎操做已抽象到基類,因爲沒有什麼業務邏輯,因此是空的。
通常來講不能簡化,由於對於稍複雜的模塊,都須要往這些類中添加內容,若是沒有它們你的代碼將變得混亂,這些構造很好的組織了代碼。
除非你能肯定你的項目基本都是CRUD,這種狀況下確實能夠簡化,並且最好的辦法是採用單層架構,單層架構在高度抽象和採用代碼生成器的狀況下,開發效率猶如火箭直衝宵漢。
這兩天園子裏討論加班的不少,我也說幾句。
不加班有幾個條件:
第一點最困難,哪怕大家開發人員水平再高,框架也很強大,若是老闆要求你2個月完成8個月的工做,你不加班是不可能的。
若是計劃合理,框架很強大,你一天用半天時間來開發,半天時間休息都綽綽有餘。
本文分享了我在EF和代碼生成器上的一些見解,不見得正確,那只是我摸索的一些經驗,你應該找出最合適大家團隊和項目的方法,並持續改進。
.Net應用程序框架交流QQ羣: 386092459,歡迎有興趣的朋友加入討論。
.Net Easyui開發交流QQ羣(本羣僅限Easyui開發者,非Easyui開發者勿進):157809322
謝謝你們的持續關注,個人博客地址:http://www.cnblogs.com/xiadao521/