重温Petshop 谈谈对三层架构的理解兼发布一个通用的数据访问控件(oracle免装客户端)

    编写这个组件的需求灵感来自于看了某个产品(企业应用系统)研发项目的源码,该产品为了同时支持sql server 和oracle,

照搬了微软的 petshop的代码作为系统架构,petshop相信很多.net程序员都非常熟悉了,里面所展示的三层架构大意是这样的

UI层,BLL层,DAL层,UI层使用BLL层的服务对象,BLL使用DAL层的服务对象,其中BLL层对DAL层的引用使用的是接口,通过配置文件动态加载指定的DAL实现,

DAL通过使用不同的数据库ADO.NET组件,调用不同的SQL语句,如 Oracle DAL 使用了System.Data.OracleClient下的OracleConnection,OracleCommand...,

SQLServer DAL使用了System.Data.SqlClient下的SqlConnection,SqlCommand等,实现了针对不同数据库的支持。

于是,这个产品的开发人员,都是这么个过程编写代码的,首先,打开UI层,当需要对数据进行某项操作时,比如 GetProduct(int id) 编写好2条sql语句,1条sql server版(select * from product where id = @id),放置于一个专门存放sql server的sql语句的xml文件中,一条oracle版的(select * from product where id =:id),放置于一个专门存放Oracle的sql语句的xml文件中,然后在IDAL层定义方法接口,同时在SQL Server DAL和Oracle DAL各 定义一个实现方法执行该sql,

大致如下

 idal:

public interface  IProduct

{

 product  GetProduct(int id);

}

 

sqlserver dal:

public class ProductDal: IProduct 

 publilc product GetProduct(int id)

{

  reuturn SqlHelper.ExecuteDataSet(sqlserver.sql)...

}

}

oracle dal:

public class ProductDal: IProduct 

  publilc product GetProduct(int id)

{

  reuturn oracleHelper.ExecuteDataSet(sqlserver.sql)...

}

}

SQLhelper 代码大致如下

 public ExecuteDataSet(string sql)

{

  using(SqlConnection conn = new SqlConnection)

 {

.....

}  

}

Oraclehelper 代码大致如下

 public ExecuteDataSet(string sql)

{

  using(OracleConnection conn = new SqlConnection)

 {

.....

}  

}

然后再在BLL层定义方法,

idal = DALFactory.DataAccess.CreateProduct();  (通过配置文件指定返回实现的DAL)

 publilc product GetProduct(int id)

{

  reuturn idal.GetProduct(id);

}

至此,UI层终于可以调用BLL的方法了。结果就是 DAL层庞大无比,有无数个类和方法,而BLL呢,没有实质性代码,简直就是为了达到三层架构而拼凑出来似的,纯粹就是为了"三层"而"三层"。

事实上,我认为,数据层应该提供的是数据服务,即每个数据库对象(表,视图,存储过程)的crud,而和业务逻辑无关,而BLL通过调用这些数据服务,形成UI层需要的数据,并返回给UI,而UI层,只负责响应界面上用户的操作,对数据的加工处理,则交给BLL完成,这才是三层的分工职责。

像上面误解三层架构的地方其一是 没有真正理解数据访问层的负责提供数据服务的概念,实质上是把ui层需要什么都数据,都交给数据访问层去实现,petshop作为一个示例代码项目,为了通俗易懂,bll写的比较简单,却给一些人造成了误解,以为bll就是一个代理层。

其二是如果为了使产品适应不同的数据库,这种架构未免太罗嗦,首先要定义接口,然后针对sql server写一个实现方法, 然后针对oracle再写一个实现方法, 方法内容大多数情况下一模一样的,实际上微软的ADO.net组件里早就提供了一组通用的抽象基类,位于System.Data.Comm下,DbConnection,DbCommand...,  System.Data.SqlCient和System.Data.OracleClient下的SqlConnection,OracleConnection均继承于对应的抽象基类,微软设置连创建这些组件的工厂类都建立好了,DbProviderFacoty,实现子类SqlClientFactory,OracleClientFactory...,事实上,我们完全可以用使用通用ADO.net组件来编写我们的

xxxDBHelper类,这样对于dal,无需使用接口,无需多个针对数据库的实现,

比如 

DBHelper:

 public ExecuteDataSet(string sql)

{

  using(DbConnection conn = DbProviderFacory.Instance.CreateConnection())

 {

....

}

DAL里不必再考虑多个库的实现,直接

DBHelper.ExecuteDataSet(sql);

我们需要做的,无非就是在初始化的时候,创建指定的DbProviderFacory,实际上配置文件的数据库连接里就有

ProviderName这一项,就是用来指定DbProviderFacory(微软其实已经提供了我们所需要的一切),而在machine.config,已经内置了微软的针对不同数据库的DbProviderFacory,如SQL Server,Oracle,OleDb,ODBC等,

说得简单点,只要我们在配置文件的数据库连接配置里,填上连接字符串,填上ProviderName,我们就能根据

ProviderName得到我们的DbProviderFacory,然后通过DbProviderFacory创建我们执行sql需要的Connction,Command等ADO.net 对象,我们在代码中无须再关心数据库的异同。

所以,我编写了DBClient,里面主要就一个类,DataAccess,提供的功能类似于petshop里面的sqlHelper,oracleHelper,只不过我使用的DbConnection,DbCommand等,

使用起来很简单,

DataAccess dataAccess = new DataAccess(providerName, connstring);

dataAccess.ExecuteDataSet(sql)....

你的providerName指向的是oracle provider,就会创建出oracle的ado组件执行sql,指向sql server provider,则会创建出sql的ado组件执行sql。

另外,在oracle provider我使用了oracle官方的oracle.dataaccess.dll,不仅性能和稳定性比微软自己的system.data.oracleclient.dll强(微软已宣布停止了该组件的发布),而且运行时带上相关的dll,还能免装

oracle 的客户端。

原文地址:https://www.cnblogs.com/lindping/p/2090834.html