NET 分布式架构开发实战之三 数据访问深入一点的思考_第1页
NET 分布式架构开发实战之三 数据访问深入一点的思考_第2页
NET 分布式架构开发实战之三 数据访问深入一点的思考_第3页
NET 分布式架构开发实战之三 数据访问深入一点的思考_第4页
NET 分布式架构开发实战之三 数据访问深入一点的思考_第5页
已阅读5页,还剩4页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

[原创].NET分布式架构开发实战之三数据访问深入一点的思考.NET分布式架构开发实战之三数据访问深入一点的思考前言:首先,感谢园子里的朋友对文章的支持,感谢大家,希望本系列的文章能够真正的对大家起到一点帮助的作用。再次感谢大家。大家也许想问,什么时候出代码,代码一定会出的,我不想一上来就开始抛出一大堆的代码,然后讲解,架构的设计在思考的过程,思考到了,代码也就水到渠成了。上篇文章讲述在设计之初,Richard所画出的一些草图,本篇对之前的草图做了进一步的思考。本篇的议题如下:.草图的一些问题在哪里重审之前项目中数据层的问题思维的一点突破回首再看数据访问层1.草图的一些问题在哪里当Richard把草图画出来了之后,想到了另外的一个问题:在DAL数据层之间提供的那个接口层到底应不应该是ServicesInterface。其实这个接口层是普通的Interface层还是ServicesInterface,Richard也拿不定主意的,因为当初之所以要把这个接口层改为ServicesInterface,是因为在数据源提供者(ServiceAgent)那块给了他“灵感”——数据源可以使用远程的Services。基于这个思想,所以Richard也考虑到了:也许,现在设计的这个DAL,哪一天会作为服务给其他的程序提供数据也不说定。虽然,这个问题对现在来说不是那么的重要,但是在Richard的心里,无法说服自己到底使用哪一种接口层(也许是Richard这个人的性格有关吧,一定要给个理由说服自己,但是这个理由又不能随随便便的糊弄自己)。Richard想到了之前在开发项目的时候,也确实曾经把其他公司提供的服务作为数据源的情况。当时的调用虽然只是进行查询,增加,删除,修改的简单操作,但是很多的流程已经在服务提供者那边定义好了,例如在发送一批货物的时候,Richard只是调用了服务接口的一个CreateProduct(Productproduct)方法,但是在服务器那端却做了很多的事情:计算库存,生成订单,选择货物供应商等等。这样说来,如果现在Richard把DAL上面加上一个ServicesInterface层,那么DAL或者其他的层就必须提供很多的逻辑操作,或者不一定是逻辑操作,还可以是数据格式验证、身份验证。如果真的这样设计,那么数据层的做的事情就很多了,要很多的逻辑。而这些逻辑在BLL中进行才是比较好的选择,想到这里,Richard似乎开始明白:把ServicesInterface层放在BLL层之上。这样就可以充分的利用BLL的逻辑验证功能。所以DAL之上的接口层,还是决定采用普通的接口。2.重审之前项目中数据层的问题Richard在数据层DAL这块花了大量时间来思考,其实是有原因的。在之前的项目中,数据层的设计显得很臃肿,而且在Richard看来,这些代码已经可以用一种比较通用的方式来写,没有必要写那么复杂的代码。例如,在EmployeeDAL中有以下的方法:代码publicEmployeeGetEmployeeById(stringemployeeId);publicEmplpyeeGetEmployeeByName(stringemployeName);publicstringGetEmployeePositionById(stringemployeeId);publicintGetEmployeeCount();这样写,没有错。但是有一点引起了Richard的思考:DAL类中,很多的方法基本上都是查询的方法,而Add,Update,Delete在很多的DAL类中形式都比较的统一,特别是在使用了Linq,EntityFramework之后,所有的数据实体类Add,Update,Delete方法几乎是一样的,如在Linq中可以使用DataContext.GetTable<T>().InsertOnSubmit(entity)方法来插入任何的数据实体类。但是就只有这些不同条件的查询方法很难统一,几乎是每个不同的DAL都要去实现自己的一些特有的查询方法。但是Richard认为把这些方法统一是有可能的,甚至是达到那种“以不变应万变的”效果才好,带着这个想法Richard开始进行很多的尝试。3.思维的一点突破Richard极力的在自己的脑海搜寻解决的方案,也翻阅自己之前下载和买过的书籍,看看那些是否与查询数据有关,只要看到有“查询”两个字的章节,Richard就不会放过。也参看了.NET的一个知名开源Framework的设计思想。给了他提示的就是Fowler<<企业应用架构模式>>一书,书中提到的查询对象(QueryObject),Richard参看了之后第一反应就是:确实不错,但是太抽象了,没有给出一些示例。其实之前Richard在看这本书的时候,认为书的高度太高了,Richard几次攻读,都是深受打击。所以,结果是Richard很敬畏这本书,但是还是想有朝一日能够拿下它。现在书中就有了查询对象的一些解决方案和实现,Richard硬着上了。Richard认为:很多的事情不是等你的所有条件都具备才去做的,事情往往是在你还没有准备好的情况下就已经发生了,凡事都有一个开头,做架构也是这样的,开始设计一个架构的时候,并且不是说明你已经完全的把所有技术都掌握了,完美了,肯定是有一个开始尝试的过程。可能在开始设计的时候,漏洞百出,但是思维的周密性也是这样慢慢的锻炼出来的。平时在思考的时候,自己站在一个高一点的角度看问题(现在是开发人员,但是开发人员在设计和开发的时候可以这样想:如果我是架构的设计者,我会怎么做?),思维的高度上去了,机会到来的时候也就从容了。Richard开始重新理解查询对象。其实查询对象就是在一定程度上隐藏了SQL语句,查询对象是解释器模式的一种应用,实际上查询对象最后还是要解释为SQL语句到数据库中去执行的(不管在中间过程是如何一步步的操作这个查询对象,因为数据库现在只是认识SQL,所以查询对象最终还是要生成SQL语句)。查询对象主要用途就是使得客户程序可以构造各种的查询,而且查询中使用的都是与业务类有关的属性,这就意味着,客户程序不用了解数据库的表名和列名。这种做法最直接的好处就是业务开发的人员不用知道数据库的构造。而且如果查询对象的设计是以接口的形式出现,那么灵活性就更加的大。例如,设计一个IQuery的查询对象接口,然后,在架构中有两个实现了IQuery接口的查询对象,如LinqQuery,EFQuery,这两个具体的查询对象最终会被分别解释为Linq和EntityFramework可以识别的语句,再通过Linq和EntityFramework去执行数据操作。在程序中就可以通过配置来决定使用哪种查询对象和使用哪种数据访问技术。越来越多的想法在Richard的脑海中出现,而随之带来的问题也开始堆积。基本的思想是有了,但是实现起来那就得是另外的一回事了。怎么把这些思绪理清,怎么把这些理清的思绪变为代码的实现,这个成为了摆在Richard面前最现实的难题。但是不管怎样,已经有了一点点的进展,记得当初考虑的时候还是头脑一片空白,现在的想法一个接着一个,在思维上进步了。Richard觉得有点欣慰。4.回首再看数据访问层有了上面的思考,Richard再次审视了DAL,开始发觉:DAL其实就只是一个存取数据和操作数据的地方,这就是DAL的主要功能。现在数据层的设计基本上已经可以实现了,而且可以做到“以不变应万变”,不管BLL中对数据进行什么样的操作,在DAL层都可以用那个四种增,删,查,改的方法搞定。本篇就到这里,谢谢各位!下篇讲述:.NET分布式架构开发实战之四构建从理想和实现之间的桥梁[原创].NET分布式架构开发实战之四构建从理想和实现之间的桥梁(前篇).NET分布式架构开发实战之四构建从理想和实现之间的桥梁(前篇)前言:上一篇文章讲述了一些实现DAL的理论,本篇主要是DAL实现的的初步的尝试。本篇的主要议题如下:1.设计DAL的基本操作2.对基本的操作的进一步的思考3.查询对象的一些思考1.设计DAL的基本操作Richard认为:在设计一个架构或者Framework的时候,有几点很重要:a.总体把握的能力。b.抽象的能力。c.分析的能力首先,从总体上来看,Richard认为DAL中最基本,而且最容易想到的方法就是CRUD(Create,Read,Update,Delete)四个操作。于是Richard在草纸写出了基本操作的名称:AddSingleDataEntity;AddDataEntityList;UpdateSingleDataEntity;UpdateDataEntityList;DeleteSingleDataEntity;DeleteDataEntityList;GetSingleDataEntiry;GetDataEntityList;上面列出的方法名字很长,其实Richard在思考这些方法的名称的时候也参考了.NET设计规范中的一些建议:方法名称要具有“自解释性”,因为架构的设计最后还是给开发人员用的,所以方法的定义要一眼就看出它是干什么的,而且规范的命名也可以大大的减少维护的成本。(可能这些名字的命名有点对规范的“生搬硬套”,但是之后会慢慢的重构的)从总体出发,已经定义出了基本的操作,那么现在就开始一步步的分析,如何实现这些方法。Richard开始思考第一个方法的实现,其实Richard心里也清楚:其实到底哪个方法作为第一个来考虑也许很重要,但是在一切都不清楚之前起码要拿一个来入手,而且随着思考的深入,很多的问题都会慢慢的浮现,到时候一切就会明晰起来。对于AddSingleDataEntity这个方法,首先就要考虑这个方法到底要把什么添加到数据库中,也就是说要考虑这个方法的参数,而且这个参数要足够的“兼容”,因为之前Richard就是想设计出一个“以不变应万变”的DAL。在考虑这个参数问题之前,首先Richard很清楚:在.NET数据访问技术中,Linq,EntityFramework等ORM技术已经广泛的应用,所以在设计DAL的时候要充分的考虑到现有的一些技术(尽量避免重新造轮子)。而且在数据是如何被存入到数据库中的以及数据是如何从数据库中取出的,这个工作是完全可以交给这些ORM的,最后的结果就是:在DAL中只是操作这些ORM的那些映射实体。基于这个想法,Richard就确定了:AddSingleDataEntity参数是一个数据实体。(本系列文章约定:数据实体,即DataEntity,就是ORM对一个数据库表进行映射后产生的实体和数据库中的表一一对应,如在数据库中有一张Employee表,LinqtoSql将会把它映射成为Employee的一个类,这个类就称为数据实体)。因为这些方法最终是操作数据实体的,所以包含这些方法的接口名字就定义为IDataContext。因为不同的表产生不同的数据实体,但是Richard还想使得AddSingleDataEntity这个方法可以接受任何的数据实体,所以此时很有必要对数据实体进行抽象。所以Richard想到了定义一个接口:IDataEntity,打算让所有通过ORM生成的数据实体都继承这个接口。而且Richard还想到:1.如果BLL直接引用DAL使用的,那么IDataEntity可能会在BLL中出现的。2.如果BLL通过repository去DAL中获取数据,那么到时候BLL可能都不会直接引用DAL,但是BLL最终还是得使用数据做事情,所以IDataEntity还是会在BLL中出现,所以,IDataEntity接口最好定义在一个公共的地方。Richard决定新建一个Common的类库,加入IDataEntity接口的定义,现在这个接口里面什么都没有,只是一个标记而已,表明继承这个接口的类就是数据实体类。AddSingleDataEntity(IDataEntitydataEntity);还有一点就是尽量的使用类型安全的方法,于是Richard把方法改成了范型方法:AddSingleDataEntity<T>(TdataEntity)whereT:IDataEntity,class,new();至于T的那些约束:T:IDataEntity,class,new(),是考虑到了Linq和EF中对数据实体的一些要求。一般的Add方法都是返回添加是否成功,true或者false,方法再次改造:boolAddSingleDataEntity<T>(TdataEntity)whereT:IDataEntity,class,new();然后Richard就写出了上面列出的一些方法的定义:boolAddSingleDataEntity<T>(TdataEntity)whereT:class,IDataEntity,new();boolAddDataEntityList<T>(List<T>dataEntityList)whereT:class,IDataEntity,new();boolDeleteDataEntityList<T>(List<T>dataEntityList)whereT:class,IDataEntity,new();boolDeleteSingleDataEntity<T>(TdataEntity)whereT:class,IDataEntity,new();boolUpdateSingleDataEntity<T>(TdataEntity)whereT:class,IDataEntity,new();boolUpdateDataEntityList<T>(List<T>dataEntityList)whereT:class,IDataEntity,new();至于GetDataEntityList,按照之前的查询对象的想法,传入一个IQuery的接口:List<T>GetDataEntityList<T>(IQueryquery)whereT:class,IDataEntity,new();2.对基本的操作的进一步的思考确实,上面那些基本操作是没有什么问题的,现在Richard又考虑到了另外的一些问题,还是以AddSingleDataEntity方法为例:a.有些时候,不仅仅要知道插入数据是否成功,而且还想返回新加入数据在数据库中的主键信息来做其他的用途。怎么办?再来查询一次?b.如果插入失败了,仅仅只是返回一个false吗?可能其他的调用模块想知道到底是发生了什么异常而导致的插入失败,而且其他的模块对于发生的异常有自己的处理方法,所以AddSingleDataEntity要提供足够的信息。基于上面的思考,所以这个基本的操作方法不能只是简单的返回一些简单的值就完了。也就是说,这些方法要返回一个数据包:里面包含很多信息,以便其他的调用模块来使用这些信息,感觉有点像是C#事件中的eventArgs.所以Richard在Common的那个类库中加入一个对象,定义如下:代码publicclassDataResult<T>whereT:IDataEntity{publicList<T>EntityList{get;set;}publicboolIsSuccess{get;set;}publicExceptionException{get;set;}publicobjectCustomData{get;set;}}这个类最后将会作为方法的返回结果。Richard发觉,上面的方法确实是很有”自解释性”,但是很多的开发人员对这些CRUD操作的名字都很熟悉了,而且最后开发的出来的架构的使用者还是开发人员,应该符合他们的习惯,所以Richard改变了方法的名字,改变后的版本如下:代码publicinterfaceIDataContext{IList<T>Query<T>(IQueryqueryCondition)whereT:class,IDataEntity,new();IList<T>Que

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论