在上一篇我们知道,要解除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
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace IDAL { public interface IDALBasewhere T : class { /// /// 向T对应的数据表插入 /// 一条数据 /// /// /// true:成功,false:失败 bool Insert(T entity); /// /// 修改数据表中与entity /// 实体对应的记录 /// /// /// true:成功,false:失败 bool Update(T entity); /// /// 删除数据表中与entity /// 实体对应的记录 /// /// /// true:成功,false:失败 bool Delete(T entity); /// /// 查询数据库表中指定的ID /// 的记录 /// /// 标识ID /// 指定ID记录对应的实体 T Query(int ID); } }
因为,我们的接口是面向数据访问层的所有对象,所以我们采用了范型。接着我们思考一下,除了我们全局接口所定义的方法,我们有些数据访问类可能还有一些自己特有的公共方法,这些方法也必须用接口的形式暴露出来,因为我们BLL层并没有引用DAL层,所以它是个只认接口的家伙,接口没有定义的方法,它就不会去调用,综上我们必须为每个DAL数据访问实体提供相应的接口,并且该接口里面必须涵盖数据访问类型中的所有方法,例如我定义了一个IOrder接口,如下
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Model; namespace IDAL { public interface IOrderDAL : IDALBase{ } }
它仅仅只是继承了全局接口,假设我们的数据访问类型Order有一个全局接口没有定义的方法如GetAllOrder(),那么在IOrder接口中必须定义出GetAllOrder()。
至此,我们的接口已经定义完成了,下面我们就要考虑封装我们的DAL了。很明显,所有的数据访问类型都继承了IDALBase
using System; using System.Collections.Generic; using System.Linq; using System.Text; using IDAL; namespace DAL { public class DALBase:IDALBase where T:class { protected IDALBase dalActive; public bool Insert(T entity) { return dalActive.Insert(entity); } public bool Update(T entity) { return dalActive.Update(entity); } public bool Delete(T entity) { return dalActive.Delete(entity); } public T Query(int ID) { return dalActive.Query(ID); } } }
从上面可以看到,我并没有直接在基类里面手写实现接口的代码,而是调用了基类中另一个IDALBase
在DAL层我提供了两个实现类,一个是ADOBase
using System; using System.Collections.Generic; using System.Linq; using System.Text; using IDAL; namespace DAL { public class ADOBase: IDALBase where T : class,new() { #region ADO.net操作数据库的基本API //在这一部分需要提供各类操作数据的API,作用主要有两个: //第一,调用这些API实现IDALBase 接口 //第二,对于所有继承自DALBase的数据访问层实体, //他会取得该dalActive实体,让后强行转换为ADOBase对象 //调用此类API,实现其特有的功能 #endregion #region 实现接口 public virtual bool Insert(T entity) { //采用ADO实现 return true; } public virtual bool Update(T entity) { //采用ADO实现 return true; } public virtual bool Delete(T entity) { //采用ADO实现 return true; } public virtual T Query(int ID) { //采用ADO实现 return new T(); } #endregion } }
另一个则是EFBase
using System; using System.Collections.Generic; using System.Linq; using System.Text; using IDAL; namespace DAL { public class EFBase: IDALBase where T : class,new() { #region EF操作数据库的API //这里面需要提供EF操作数据库的各类方法 //函数 #endregion #region 调用EF操作数据库的API实现接口 public virtual bool Insert(T entity) { //采用EF return true; } public virtual bool Update(T entity) { //采用EF return true; } public virtual bool Delete(T entity) { //采用EF return true; } public virtual T Query(int ID) { //采用EF return new T(); } #endregion } }
好了现在基类我们有了,那么我们的子类则只需要在继承基类的同时,实例化dalActive属性,就自动的实现了IDALBase
为了使我们的程序变的灵活,支持各类数据访问技术,我们利DalActiveProvider的静态方法来实例化我们基类中的dalActive属性,该方法通过读取配置文件来判断,给dalActive创建何种类型的实例,本文你只提供了两种实例(EFBase
using IDAL; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Text; namespace DAL { public class DalActiveProviderwhere T:class,new() { private static string className = ConfigurationManager.AppSettings["dalActiveName"]; public static IDALBase GetDalActive() { if (string.Equals(className, "EFBase")) { return new EFBase (); } else { return new ADOBase (); } } } }
下面我定义了一个OrderDAL数据访类
using Common; using Factory; using IDAL; using Model; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DAL { public class OrderDAL : DALBase, IOrderDAL { public OrderDAL() { this.dalActive = DalActiveProvider .GetDalActive(); } #region 专有公共方法 //根据技术的选型 //将dalActive强行转换 //为ADOBase 或者EFBase,在调用其 //数据访问API来实现专用公共方法 #endregion } }
我们的配置文件,如图
很显然,目前我们会创建EFBase