接上一篇我们来对数据访问层进行封装与抽象。在上一篇我们知道,要解除BLL对DAL的依赖,我们就必须抽象出DAL层的接口,同时基于DAL的数据访问技术很多,如EF,ADO.NET,LINQ TO SQL,因此,我们的数据访问层必须对这些技术提供相应的支持。所以今天我们要做的事情有两件,第一,定义我们的数据访问层接口;第二,屏蔽各类数据库访问技术的差异,提供统一的数据库访问模型。举个例子,我们只需要修改一下我们的配置文件,就能够把ADO.NET的实现方式,改变成EF的实现方式。好下面搭建我们的三层构,如图:
项目的框架与上一篇基本一致。项目的引用关系: StructUI->Common,Model,BLL; BLL -> Model,IDAL,Common,Factory;DAL-> IDAL,Model。再次提醒各位,我们在BLL层并没有引用DAL,我们不能创建(new)DAL层的任何实体。
下面,我们来定义DAL层的接口。定义层次的接口其实是一件很复杂的事情,首先,我们必须抽象出该层内所有对象有的属性与行为。对于数据访问层的对象,很明显增删改查是肯定走不掉的。其次我们必须充分的考虑,数据访问层各类技术对该接口的实现难度,技术上没法实现的接口,肯定是没有任何意义的。本文仅当示范作用,所以暂时我定义的接口会很简单,在后续的章节,我会抽象出一套完备的数据接口。该层的任何实体,都具备增删改查功能,所以我们首先定义该层的全局接口IDALBase<T>,即任何数据访问实体,都应该实现的接口,代码如下
因为,我们的接口是面向数据访问层的所有对象,所以我们采用了范型。接着我们思考一下,除了我们全局接口所定义的方法,我们有些数据访问类可能还有一些自己特有的公共方法,这些方法也必须用接口的形式暴露出来,因为我们BLL层并没有引用DAL层,所以它是个只认接口的家伙,接口没有定义的方法,它就不会去调用,综上我们必须为每个DAL数据访问实体提供相应的接口,并且该接口里面必须涵盖数据访问类型中的所有方法,例如我定义了一个IOrder接口,如下
它仅仅只是继承了全局接口,假设我们的数据访问类型Order有一个全局接口没有定义的方法如GetAllOrder(),那么在IOrder接口中必须定义出GetAllOrder()。
至此,我们的接口已经定义完成了,下面我们就要考虑封装我们的DAL了。很明显,所有的数据访问类型都继承了IDALBase<T>接口,那么有一点可以肯定,就是所有的数据访问类型都必须提供IDALBase<T>的实现代码,这个时候我们就必须设想一下,我们能否抽象出一个公共的基类,来帮我们实现IDALBase<T>接口呢?如果能的话,将极大的降低我们的代码冗余,使我们的程序变的优雅,下面我提供一个基类DALBase<T>
从上面可以看到,我并没有直接在基类里面手写实现接口的代码,而是调用了基类中另一个IDALBase<T>类型的实体(dalActive)来帮助我们实现实现接口。这是为什么呢? 在前面我们说过,我们要让我们的DAL层支持各类的数据访问技术。大家想想,如果我们在基类里面,采用了一种技术如ADO.NET去把接口给实现了,那么很显然,我们这个DAL将不再支持任何其他的数据访问技术,因为我数据访问层的所有类型都继承了这个基类,基类的数据访问技术定型了,子类将根本没的选。所以我们在这里定义了一个IDALBase<T>类型的属性,让它来帮我们实现我们的接口。
在DAL层我提供了两个实现类,一个是ADOBase<T>,采用了ADO.NET技术,该类不仅仅提供给接口的实现,还提供ADO.NET操作数据库的基本API。由于该系列是我前不久才开始写的,没有现成的Doom,所以暂时只能拿出一个阉割版本了,但是该类要实现一些什么样的功能,我已经用注释说明了,在下一篇,我会提供它的具体实现。
另一个则是EFBase<T>,采用是EF技术,并提供EF操作数据库的API。供DALBase<T>子类去实现其专有的方法。
好了现在基类我们有了,那么我们的子类则只需要在继承基类的同时,实例化dalActive属性,就自动的实现了IDALBase<T>接口,同时根据dalActive的类型的不同,我们的子类还具备不同的数据库访问方式(ADO.NET,EF),这是因为我们子类可以从父类的dalActive属性实体拿到其对应数据访问技术的API,我们只需强行转换一下dalActive。例如:将dalActive强转为EFBase,就可以得到EF的数据访问API(当然dalActive必须是EFBase类型)。
为了使我们的程序变的灵活,支持各类数据访问技术,我们利DalActiveProvider的静态方法来实例化我们基类中的dalActive属性,该方法通过读取配置文件来判断,给dalActive创建何种类型的实例,本文你只提供了两种实例(EFBase<T>与ADOBase<T>)所以相对简单,如下
下面我定义了一个OrderDAL数据访类
我们的配置文件,如图
很显然,目前我们会创建EFBase<T>实例给基类的dalActive属性,整个DAL层将采用EF数据访问技术,如果我们想采用ADO.NET技术的话,我们只需要将配置文件的dalActiveName的Value改为与字符创“EFBase”不等的任何字符串即可。
至于BLL层如何调用DAL层,在我的上一篇文章已经做了详细的介绍,所以我不多说了,工厂代码如下
我在BLL层创建了一个很简单的基类BLLBase<T>,里面只有一个实现IDALBase<T>接口的属性dalService,如下
在BLL的我创建一个业务子类OrderBLL继承BLLBase<T>,在构造函数中采用工厂实例化dalService,然后OrderBLL针对数据库的所有操作都是调用dalService的对应方法。当然,如果OrderBLL需要调用一些OrderDAL的专有方法,我还必须把dalService强行转换为IOrderDAL接口类型
总结
本文对数据访问层进行了概要上的封装与抽象。当然在定义接口方面我们做的很简单,在后面的章节我会完善并抽象出一个相对完备的接口,另外对于DAL的封装我们还有两大核心类(EFBase<tT>与ADOBase<T>)没有去实现,对于这两个类的实现将会是我随后的几篇博文的核心课题,最后感谢大家的观看
本文的DOME 在这里