2 约定
(1)本文中谈及的数据库仅限于关系数据库。数据库类型指不同的关系数据库系统,如Oracle,SQL Server,Sybase等等。
(2)数据库对象指ADO.NET中访问数据库的对象:Connection对象,Command对象,Adapter对象、Parameter对象。
3 应用程序的一般结构
通常,数据库相关的应用程序应该具有图1所示的结构。至于为什么,就不用多说了。从图中可以看到数据库访问层所处的位置,及其应该具有的功能。
图1 应用程序一般结构
4 适应不同类型的数据库
如第1节所述,在ADO.NET中,使用不同类型的数据库,主要就是这些数据库对象的变化:Connection,Command,Adapter,Parameter。在程序中我们需要根据不同的数据库创建合适的对象。
通常的简单做法是使用条件判断,是何种类型的数据库,创建相应的数据库对象,代码如下:
[示例代码1] 简单,但缺乏弹性和复用性的方法
///
/// 数据库类型。
///
public enum DbType
{
SqlServer,
Oracle,
OleDb,
}
class DbObjectFactory
{
///
/// Connection 对象的创建。
///
/// 数据库类型。
///
public static IDbConnection CreateConnection(DbType dbType)
{
switch(dbType)
{
case DbType.SqlServer:
return new SqlConnection();
case DbType.Oracle:
return new OracleConnection();
case DbType.OleDb:
return new OleDbConnection();
}
throw new Exception("不支持的数据库类型。");
}
///
/// Parameter 对象的创建。
///
/// 数据库类型。
///
public static IDataParameter CreateParameter(DbType dbType)
{
switch(dbType)
{
case DbType.SqlServer:
return new SqlParameter();
case DbType.Oracle:
return new OracleParameter();
case DbType.OleDb:
return new OleDbParameter();
}
throw new Exception("不支持的数据库类型。");
}
}
上面的代码中都是条件判断,而且CreateConnection函数和CreateParameter函数代码几乎一样,DataAdapter和Command的创建也是如此。这样的做法缺点主要有两点:
(1)代码重复,可维护性差;
(2)新增加一种数据库类型时,需要修改现有的代码。
其实我们仔细分析以下数据库类型和对象之间的关系,可以发现图2所示的规律:
图2 不同数据库和对象的关系
很明显,采用抽象工厂模式可以很好的处理不同数据库和不同数据库对象之间的组和系列的关系。如图3:
图3 数据库对象工厂设计
根据上面的类图,生成C#代码如下:
[示例代码2: DbObjectFactory.cs] (有删节)
///
/// 数据库对象工厂的虚基类。
///
public abstract class DbObjectFactory
{
///
/// 创建数据库连接对象,并打开连接。
///
///
public abstract IDbConnection CreateConnection();
///
/// 创建Command 对象。
///
///
public abstract IDbCommand CreateCommand();
///
/// 创建DbDataAdapter 对象。
///
///
public abstract IDbDataAdapter CreateDataAdapter();
///
/// 创建Parameter 对象。
///
///
public abstract IDataParameter CreateParameter();
}
[示例代码3: OleDbObjectFactory.cs] (有删节)
///
/// OleDb 数据库对象工厂。
///
public class OleDbObjectFactory : DbObjectFactory
{
///
/// 创建数据库连接对象,并打开连接。
///
///
public override IDbConnection CreateConnection()
{
return new OleDbConnection();
}
///
/// 创建Command 对象。
///
///
public override IDbCommand CreateCommand()
{
return new OleDbCommand();
}
///
/// 创建DbDataAdapter 对象。
///
///
public override IDbDataAdapter CreateDataAdapter()
{
return new OleDbDataAdapter();
}
///
/// 创建Parameter 对象。
///
///
public override IDataParameter CreateParameter()
{
return new OleDbParameter();
}
}
[示例代码4: OleDbObjectFactory.cs] (有删节)
///
/// Sql Server 数据库对象工厂。
///
public class SqlObjectFactory : DbObjectFactory
{
///
/// 创建数据库连接对象,并打开连接。
///
///
public override IDbConnection CreateConnection()
{
return new SqlConnection();
}
///
/// 创建Command 对象。
///
///
public override IDbCommand CreateCommand()
{
return new SqlCommand();
}
///
/// 创建DbDataAdapter 对象。
///
///
public override IDbDataAdapter CreateDataAdapter()
{
return new SqlDataAdapter();
}
///
/// 创建Parameter 对象。
///
///
public override IDataParameter CreateParameter()
{
return new SqlParameter();
}
}
使用时,根据应用环境的数据库类型,创建相应的具体工厂对象即可。这样就避免了使用生硬的条件判断了。新增加一种类型的数据库时,只要添加一个类,从DbObjectFactory继承即可,而现有的代码不需要做任何的修改。