从本篇开始,本系列将进入实战演练阶段。程序员
前面主要介绍了一些应用程序框架的概念和基类,原本想把全部概念介绍完,再把框架内部实现都讲完了,再进入实战,这样可让初学者基础牢靠。不过个人精力颇有限,文章进度愈来愈慢,因此准备切换一下介绍顺序,把实战演练提早,以方便你阅读代码。数据库
本系列实战演练共分两个部分。编程
实战演练第一部分介绍如何快速解决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/