在很多应用系统里面,虽然一般采用一种数据库运行,但是由于各种情况的需要,可能业务系统会部署在不同类型的数据库上,如果开发的系统能够很方便支持多种数据库的切换,那可以为我们减少很多烦恼,同时提高系统的适应性和强壮型。还有一种情况,由于业务数据库的不断膨胀或者方便数据库的切割隔离,有时候也会把不同的业务数据库进行分拆,如权限提供数据库,客户关系管理数据库,工作流程数据库,企业营运数据库等等,因此在一个系统里面,同时使用2个或者以上的数据库的情况也是有的。
在我较早期的一篇随笔《Winform开发框架中实现多种数据库类型切换以及分拆数据库的支持》里面,介绍了框架如何在一个项目里支持多个数据库的拆分处理。一般情况下,我们都是在一个数据库类型的情况下,分拆多个数据库,但是也有变态的需求例外,如我们可能把一些常规的数据库存储在本地SQLite数据库里面,其他的一些数据放在局域网其他类型数据库(如SQLServer)里面;那么这种同一时刻支持多种数据库类型,并且给用户创建BLL层类的时候,动态指定数据库是否可以实现的呢?
当然可以,我们在上面的基础上稍微调整一下创建方法即可。
之前介绍了,需要分拆数据库的话,我们需要在数据访问基类AbstractBaseDAL里面,添加一个SetConfigName的方法,用来指定具体的数据库配置项目,如下所示。
/// <summary> /// 数据访问层的超级基类,所有数据库的数据访问基类都继承自这个超级基类,包括Oracle、SqlServer、Sqlite、MySql、Access等 /// </summary> public abstract class AbstractBaseDAL<T> where T : BaseEntity, new() { /// <summary> /// 设置数据库配置项名称 /// </summary> /// <param name="dbConfigName">数据库配置项名称</param> public virtual void SetDbConfigName(string dbConfigName) { this.dbConfigName = dbConfigName; } .................... }
那么我们这次只需要在这个基础上调整一下就可以实现同一时刻变换不同数据库支持的了,由于在框架里面,我们一般已经实现了多种数据库访问的逻辑(如下所示),因此切换起来访问肯定也是没问题的(保证有数据库即可)。
方法就是在BLL层里面添加一个公开方法,可以设置配置项和数据库类型的函数,如下所示。
/// <summary> /// 根据参数信息,重新初始化数据访问层(例:可以指定不同的数据访问层) /// </summary> /// <param name="dbConfigName">数据库配置项名称</param> /// <param name="componentDbType">数据库类型,默认从ComponentDbType中读取,如果dbConfigName指定不同类型的数据库连接,需要指定componentDbType。</param> public void SetConfigName(string dbConfigName, string componentDbType = null) { //componentDbType = null时,从配置项取ComponentDbType的值 string dbType = componentDbType; if (string.IsNullOrEmpty(componentDbType)) { AppConfig config = new AppConfig(); dbType = config.AppConfigGet("ComponentDbType"); } string DALPrefix = GetDALPrefix(dbType); this.dalName = bllFullName.Replace(bllPrefix, DALPrefix);//替换中级的BLL.为DAL.,就是DAL类的全名 baseDal = Reflect<IBaseDAL<T>>.Create(this.dalName, dalAssemblyName);//构造对应的DAL数据访问层的对象类 if (!string.IsNullOrEmpty(dbConfigName)) { baseDal.SetDbConfigName(dbConfigName); //设置数据库配置项名称 } }
这样我们除了可以设置EnterpriseLibrary的配置项外,还可以指定这个数据库的类型,不需要全部使用统一的ComponentDbType的值。
如下代码处理,我们就可以在访问其他数据库的时候,切换这个BLL层的对象为其他类型的数据库(SQLite),这样不管其他类如何变化,这个Province的数据访问的是SQLite数据库里面的数据。
BLLFactory<Province>.Instance.SetConfig("sqlite", "sqlite");
有时候,我们在一个比较小的应用程序里面,想灵活对数据库表进行一些简单的处理操作,不想使用代码生成工具生成整个架构的代码,那么这个时候,这个CommonDAL就派上用场了,这个可以快速访问数据库的表,它的定义如下所示。
这个类的几个构造函数如下所示,参数分别为表名,主键字段,数据库类型。
/// <summary> /// 默认构造函数 /// </summary> public CommonDAL() { } /// <summary> /// 指定表名以及主键,对基类进构造 /// </summary> /// <param name="tableName">表名</param> /// <param name="primaryKey">表主键</param> /// <param name="dbType">数据库类型,如果为空从配置文件里面获取ComponentDbType的键值</param> public CommonDAL(string tableName) : this(tableName, null, null) { } /// <summary> /// 指定表名以及主键,对基类进构造 /// </summary> /// <param name="tableName">表名</param> /// <param name="primaryKey">表主键</param> /// <param name="dbType">数据库类型,如果为空从配置文件里面获取ComponentDbType的键值</param> public CommonDAL(string tableName, string primaryKey, string dbType = null) : this() { }
这个就是一个精简版本的AbstractBaseDAL基类,提供了我们能够使用的多数数据库操作方法。
例如我在一个验证视图及其格式的例子程序里面,就使用了这个类来实现快速的数据库操作处理。
/// <summary> /// 判断视图名称是否存在的任务 /// </summary> public class ViewNameExistJob : IExecuteJob { public bool Execute() { List<string> list = DataHelper.GetViewList(); bool allSuccess = true; foreach (string view in list) { CommonDb dal = new CommonDb(view, "F_Guid"); try { DataTable dt = dal.GetReaderSchema(view); } catch (Exception ex) { allSuccess = false; LogTextHelper.Error(string.Format("视图:{0}不存在。{1}", view, ex.Message)); } } if (allSuccess) { LogTextHelper.Info("视图全部存在。"); } return allSuccess; } }
或者其他数据库访问处理。
CommonDb dal = new CommonDb(view, "F_Guid"); try { int count = dal.GetRecordCount(); if (count == 0) { LogTextHelper.Info(string.Format("视图【{0}】数据为空,请检查!", view)); allSuccess = false; } } catch (Exception ex) { allSuccess = false; LogTextHelper.Error(string.Format("视图:【{0}】不存在。{1}", view, ex.Message)); }
这样也可以实现多数据库的随便切换,不过这个是用于简易的数据库访问,对于需要多种业务封装的处理类,我们还是使用常规的框架分层模式来实现数据的处理操作。