在 .NET 中实现独立于提供程序的数据访问层






4.17/5 (42投票s)
2003年5月5日
6分钟阅读

345818

1426
本文介绍了如何实现一个独立于提供程序的数据访问层(DAL)。
引言
对于使用 Microsoft DNA 构建的应用程序,ADO 提供了一种最简单的数据访问方式。ADO 为开发人员提供了基于 COM 的数据访问 API,并且使用 ADO 组件可以访问多种数据源。这主要归因于 ADO 内部使用 OLEDB 提供程序连接数据源,更重要的是存在一个用于 ODBC 的 OLEDB 提供程序。这意味着开发人员也可以使用 ADO 通过连接字符串中的 DSN 连接 ODBC 源。
ADO.NET 中的数据访问方式并非完全相同。与只使用 OLEDB 的 ADO 不同,ADO.NET 提供了许多针对特定数据源的独立提供程序。例如,SQLClient 提供程序专门处理 SQL Server 7 和 SQL Server 2000 作为数据源。ODBC.NET 提供程序处理使用 ODBC 和 DSN 访问数据源。同样,OLEDB.NET 提供程序用于连接 OLEDB 数据源。此外,还存在一个独立的 .NET 提供程序用于 Oracle 数据库。
拥有独立的数据访问提供程序的好处是每个提供程序都针对特定的数据源进行了优化,并为该数据源提供最有效率的访问。例如,SQLClient 是迄今为止访问 SQL Server 7 或 2000 数据源最有效率的方式。但其缺点是开发人员可能需要决定使用特定的提供程序,而且通用的访问方式不像 ADO 那样简单。
那么,如果在应用程序运行时才决定选择提供程序呢?数据访问层(我们称之为 DAL)应该如何实现,才能让使用 DAL 的应用程序无需了解所使用的提供程序,并仍能与 DAL 无缝协作?本文将探讨 DAL 的设计和实现,以回答上述问题。
设计独立于提供程序的 DAL
编程独立于提供程序的 DAL 的关键是使用 System.Data
命名空间提供的一些接口,并且这些接口由所有提供程序实现。例如,有一个名为 IDbCommand
的接口,它表示要对数据源执行的 SQL 语句。像 SQLClient 和 OLEDB.NET 这样的提供程序,都在其各自的命令类中实现了此接口。下表显示了 DAL 中通常使用的接口。该表还给出了实现此接口的提供程序类
接口 | SQLClient 类 | ODBC.NET 类 | OLEDB 类 | 描述 |
---|---|---|---|---|
IDbConnection |
SqlConnection |
OdbcConnection |
OledbConnection |
表示与数据库的连接 |
IDbDataAdapter |
SqlDataAdapter |
OdbcDataAdapter |
OleDbDataAdapter |
表示一组用于处理 DataSet 的命令相关属性 |
IDbCommand |
SqlCommand |
OdbcCommand |
OleDbCommand |
表示要对数据源执行的 SQL 语句(或命令) |
IDataParameter |
SqlParameter |
OdbcParameter |
OleDbParameter |
表示命令对象的参数 |
IDataReader |
SqlDataReader |
OdbcDataReader |
OleDbDataReader |
表示一个或多个结果集,可以只读、只向前访问 |
IDbTransaction |
SqlTransaction |
OdbcTransaction |
OleDbTransaction |
表示要对数据源执行的事务 |
注意:Oracle .NET 数据提供程序也实现了这些接口。
现在,让我们看一个简单的例子,了解如何使用这些接口
Private Function RunCommandReturnReader(ByRef Cmd As IDbCommand,
ByRef conn As IDbConnection ) As IDataReader
Cmd.Connection = conn
Cmd.Connection.Open()
Return Cmd.ExecuteReader(CommandBehavior.CloseConnection)
End Function
上面显示的是一个执行 Command
并返回 DataReader
对象的函数。请注意,该函数分别接受 IDbCommand
和 IDbConnection
类型的两个参数,并返回 IDataReader
类型的对象。
上面显示的函数只是一个私有实用函数。在本文的后续部分,我将提供最终由 DAL 公开的函数的实现,该函数使用此实用函数返回 DataReader
对象。
Provider Factory
提供程序工厂是一个类,它公开了向调用者返回所需类型对象的方法。数据访问类使用提供程序工厂获取命令、连接对象等。数据访问类屏蔽了对象的实际类型。下面是 ProviderFactory
类的骨架
Imports Microsoft.Data.Odbc
Imports System.Data.SqlClient
Imports System.Data.OleDb
Imports System.Configuration
Public Class ProviderFactory
Public Enum EnumProviders
ODBC
SQLClient
OLEDB
End Enum
Public Shared Function GetConnection()
As IDbConnection
Select Case GetProvider()
Case EnumProviders.ODBC
Return New OdbcConnection()
Case EnumProviders.SQLClient
Return New SqlConnection()
Case EnumProviders.OLEDB
Return New OleDbConnection()
End Select
End Function
Public Shared Function GetProvider()
As EnumProviders
Dim Idt As IDictionary = _
CType(ConfigurationSettings.GetConfig("AppProvider"), IDictionary)
Return CType(Idt("Provider"), EnumProviders)
End Function
End Class
上面显示的 ProviderFactory
类包含一个 EnumProviders
枚举,列出了支持的提供程序。在此示例中,支持三个提供程序:SQLClient、OLEDB.NET 和 ODBC.NET。还公开了一个 GetConnection
方法,该方法根据应用程序配置文件中的设置返回一个连接对象。如果开发人员将其设置为 0,则 GetConnection
返回一个 ODBCConnection
对象;如果设置为 2,则返回一个 OledbConnection
对象。在上面的示例中,我们实现了一个返回连接对象的方法。以类似的方式,提供程序工厂可以实现返回 Command
、DataReader
、DataAdapter
对象等的方法。
使用提供程序工厂
请注意,提供程序工厂负责返回正确类型的对象。因此,提供程序工厂的客户端只与接口一起工作。在下面显示的示例中,我们有一个执行命令并返回 DataReader
的函数。请注意,我们之前已经处理过辅助函数 RunCommandReturnReader
Public Function RunSQLReturnDataReader(ByVal strSQL As String,ByVal
cmdtype As CommandType) As IDataReader
Dim cmd As IDbCommand = ProviderFactory.GetCommand(strSQL, cmdtype)
Dim conn As IDbConnection = ProviderFactory.GetConnection("")
Return RunCommandReturnReader(cmd, conn)
End Function
关于源代码
源代码 zip 文件包含一个 VB.NET 类库项目,其中包含简单的数据访问例程。这个助手可能无法满足企业应用程序 DAL 的所有需求,但它肯定说明了应用程序设计中类工厂模式的概念。
源代码的 V1.0 非常简单,没有做太多事情。这里的源代码是用框架的 v1.0 编译的,其中 ODBC.NET 提供程序是一个单独的下载。在框架的 v1.1 中,所有 ODBC 类现在都是 System.Data.ODBC
命名空间的一部分,该命名空间随框架一起发布。
许多读者想要一个使用 DAL 的示例应用程序。好吧,V2.0 源代码中有一个简单的应用程序,展示了 DAL 如何使用的几个实例。添加到 DAL 的许多功能包括
- ADO.NET 事务支持
- 参数缓存(基于数据访问应用程序块)
- 参数发现(基于数据访问应用程序块)
最后两个对开发人员来说应该很有趣。在示例源代码中,我并没有真正利用参数缓存和发现。在实际应用程序中,这些对应用程序非常有用,可以提高应用程序的性能,同时减少编码工作量。例如,我们可以有一个 Windows 服务,托管一个定期发现和更新的参数缓存。这样,应用程序开发人员就不需要编写任何代码来构建参数集合,只需依赖服务即可。当然,您将需要一个远程基础设施与服务通信,但这也会非常高效。
致读者:源代码中的方法签名可能与本文文本中的略有不同。但是,概念仍然相同。
其他资源
我想推荐两个关于 .NET 中数据访问的优秀资源
结论
拥有独立于提供程序的 DAL 肯定能为应用程序提供更大的灵活性,可以在运行时选择正确的提供程序,并防止应用程序的其他部分锁定到特定的提供程序。