可能只是那么想也是那么设计的,要支持多数据库,要能支持多数据库,万一要是以后数据库变了怎么办?万一要是。。。怎么办?这些顾虑很多时候是不必要的,反而绕了弯子。大都是做项目应用系统而非产品,即使要用不同的数据库了,基本上是吧上一个项目全COPY过来,修修改改OK了。产品可能就不一样了,那才可能要支持真正的多数据库,才可能会面对真正的数据库访问类库的多数据库的实际检验。ADO.NET2.0下增强了数据库访问的功能,也就是工厂式类库,提到工厂式数据库访问,网上可就多了,ADO.NET2.0增强的工厂式网上也很多了,都说只要改动webconfig里的数据库连接就行了,其它什么地方都不用改了,看了几篇都是点了下,不知道做过充分测试没有,应该说在实际的多数据库产品系统中,还要做很多修正,完善和测试的。
说正题,假设(只是假设,真的不会这么变态,呵呵)一产品系统要支持ACCESS,SYBASE,SQL SERVER,ORACEL数据库,系统开发完后,要求只改动数据库的连接,也就是说只改动webconfig,来实现系统的无缝切换,其它什么也不改动,可能有的觉得简单,但是要经得起实际检验还是要花点时间测试的,当然写是不算难,见到过有的应用系统开发中,所有的DML语句都以XML形式放在config配置文件里,然后用封装好的数据库访问组件读config配置文件执行SQL语句,开发人员只要建个config文件把增删改查语句写那里就可以,当然这么来有个好处,就是做到了与数据库的无关性了,如果数据库访问组件做的完善的,当然是可以做到系统无缝切换到其它数据库的,当然同时也有缺陷,项目中不仅仅是DML语句吧,有的稍微复杂点的逻辑,存储过程要用下吧,我自己也趋向于喜欢用存储过程,自定义函数来处理稍微复杂的逻辑,而且把DML语句都放在配置文件里我也是不能忍受的,可能是一个个人的习惯吧。
继续,下面开始我要说的利用ADO.NET2.0及以上版本新增的工厂式数据库访问实现应该系统的无缝切换,要实现无缝切换,当然还是要有前提条件了,就是各个不同的数据库之间的表和其它对象都已经成功移植了,没有这个前提,纯用ADO.NET做系统无缝切换那是不可能的了,比如SQL SERVER中写的存储过程,自定义函数直接复制到ORACLE上就行了吗?当然是不行,写法及变量定义要做些调整才可以成功移植的,还有变结构字段类型等等的都可能是要做相应调整,这些都做好了才能谈系统的无缝切换。要做的无缝切换,数据库访问层的代码中最好(并非绝对)不应该出现SqlCommand,SqlDataAdapter,SqlClient,SqlXXX吧,要切换到ORACLE数据上,甲骨文会把你的SqlXXX玩死的,ORACLE里可以OracleCommand,OracleXXX,还有程序执行带参数语句时,比如 where userid=@userid,甲骨文也会玩死你的,oracle里可是where userid=:userid,@前缀在ACCESS,SYBASE,SQL SERVER里是都认得,还有还有字段名的写法问题,ORACLE里可以区分大小写的,比如可能大多习惯这样命名属性和自段,UserName,UserAge,如果在ORACLE里这么命名的话,系统开发过程中的那种痛苦也许只有经历过的人才知道,ORACLE坚持大写为标准,记得很久很久以前的一个夏天的晚上,那时我还是年轻的80后,一位数据库设计比较N的人提到过,尽量在数据库设计和T-SQL编程中采用大写标准,基本上接触的SQL SERVER数据库较多,也习惯了表名,字段名的大写设计,后来发现确实是有道理的。这里提到的问题都是在下面的各个方法中为了兼容不同的数据库需要面对的问题,具体讲到每个执行方法时再具体解释。刚才说SqlCommand,OracleComand都是各自认得,但是DbCommand可是大家都认得的,暂且叫抽象对象吧,还有DbConnection,DbDataAdapter等都是他们都认得的,所以在做支持多数据库访问类库时,就可以用这些对象了,根据这些对象再创建具体对象。ADO.NET2.0中数据库访问工厂中有个 DbProviderFactory 对象,也就是通常说的DataProvider了,正是这个起了关键和方便的作用,是用来创建提供程序对数据源类的实现的实例(就是用来创建实例)。另外数据库操作还要用到参数吧,DbParameter,DbParameterCollection下面都需要用到,先贴一段类库的构造函数,因为共用对象需要先实例化。
复制代码 代码如下:
public DbConnection conn;//抽象类型
private DbCommand cmd;//抽象类型
private DbProviderFactory provider;
private DbParameter Para;//不同数据库参数类型的抽象类型
private DbDataAdapter Adapter;//对应不同数据库的数据适配器
Dictionary<Type, String> ParametersFormat;//不同数据库参数格式化类型
public string retParaformat = string.Empty;//最终返回的格式化标志,如@{0},:{0}
public DataProviderFactory()
{
//从配置文件中取出标示数据库类型的字符串并通过ProviderName的不同支持不同类型的数据库
string providerName = ConfigurationManager.ConnectionStrings["ConnStr"].ProviderName;//也可以用索引,从1开始
//创建一个数据库对应的实例,使用该实例就可以创建对应的connection,command 和adapater等等对象
provider = DbProviderFactories.GetFactory(providerName);
//创建具体的数据库连接类型和命令执行类型
conn = provider.CreateConnection();
conn.ConnectionString = ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString;
cmd = provider.CreateCommand();
cmd.Connection = conn;
//创建具体的参数类型
Para = provider.CreateParameter();
//创建具体的适配器类型
Adapter = provider.CreateDataAdapter();
//不同数据库参数前缀格式化
ParametersFormat = new Dictionary<Type, String>();
ParametersFormat.Add(typeof(System.Data.SqlClient.SqlCommand), "@{0}");//因SQL SERVER只返回{0}没有@前缀,在此初始化处理
//返回格式化标志
retParaformat = GetParameterFormat(cmd);
}
上面那段代码中,可以看到我定义了两个公共变量,其中conn在外部只会有一个地方调用它,那就就是执行DataReader方法的时候了,因为大家都知道dr在离开方法体时,连接是不能关闭的,
所以只能在外部调用处显示关闭连接对象 ,必须定义为公共类型了,还有一个公共参数变量是格式化字符串的字符型。前面说到Oracle参数前缀是冒号:,其它几个数据库前缀是@符号,怎么样在切换数据库以后程序能动态识别参数前缀并组合相应的参数变量呢?如果手动写代码用数据库对象类型枚举去一个个判断,那这数据库工厂也没什么意义了,最终找到了一个相当完美的解决方式(微软就是微软,都能替你想到,别人想不强大都难啦,呵呵),其实在做测试的时侯到各不同数据库的参数前缀这就有点犯难了,手写代码一个个处理吧,没问题,觉得应该有简单的方法吧,MS从来就不是傻瓜呀,正好前两天在园子首页就有篇提到这个问题,而且给出相关提示,根据给的提示再gg了一把,终于找到了一个便捷的办法。还是贴方法代码好了,如下:
复制代码 代码如下: