使用 .NET 2.0 编写通用的数据访问层






2.47/5 (16投票s)
这是一篇旨在帮助开发 .NET 2.0 或更高版本应用程序的开发人员构建通用数据访问层 (DAL) 的文章。我所说的通用是指它可以响应 .NET Framework 支持的任何数据提供程序。
引言
本文介绍了如何为小型项目(Windows 和 Web)编写一个快速轻量级的数据访问层。它很有用,因为它是一个静态类。它依赖于 *config* 文件来获取数据提供程序名称和其他连接属性。因此,您可以将此代码片段用于 .NET Framework 支持的所有类型的数据提供程序。
本文可以解决为每个使用不同数据库的项目单独重写数据访问层的问题。此外,它还包含了查询数据库时通常需要采取的所有操作。
本文使用 .NET Framework 2.0 编写,并使用了其命名空间和类。因此,.NET 1.1 Framework 用户可能需要升级到 2.0 才能使用它。
背景
在阅读正文之前,我想讨论一下抽象工厂模式,因为它有助于我们理解幕后到底发生了什么。
熟悉的人可能不需要这个,但对于其他人来说,抽象工厂通常是一个创建相似对象族的抽象类。“相似对象族”的意思是相关对象系列。就像在本例中(DbConnection
、DbCommand
、DbParameter
等)。
在我们的代码中,我们也将使用类似的抽象工厂类(System.Data.Common.DBProviderFactory
)。这个抽象工厂类将返回我们所需的所需对象。让我们在下一节中详细了解。
Using the Code
我们将深入探讨 ADO.NET 2.0 中的 System.Data.Common
命名空间。
这个命名空间在 ADO.NET 2.0 中引入,其中包含实现抽象工厂模式的类。在早期版本中,它使用接口模式。
让我们首先仔细看看 System.data.Common namespace
类。其中最重要的是 DbProviderFactory
类。这个抽象工厂类接受一个提供程序名称,并返回所有必需的 ADO.NET 类的对象。
我们首先创建一个新的类库项目。向该库添加两个类。我创建了两个类,名为 *ConnectionClass.cs* 和 *DbClass.cs*。您可以从本文上传的 zip 文件中下载这两个类文件的源代码。
让我们先仔细看看 *ConnectionClass.cs* 文件。
下面是 *ConnectionClass.cs* 的屏幕截图及其定义的一组方法。

如您所见,*ConnectionClass.cs* 包含三个方法
-
GetDbFactory()
:返回一个DbProviderFactory
对象。此方法利用System.Data.Common
命名空间中DbProviderFactories
类的static
方法GetFactory(string ProviderName)
。它返回一个DbProviderFactory
对象。internal static DbProviderFactory GetDbFactory() { try { string ProviderName = ConfigurationManager.AppSettings["ProviderName"]; DbProviderFactory Dbfactory = DbProviderFactories.GetFactory( ProviderName); return Dbfactory; } catch(DbException) { throw new Exception("An exception has occurred while creating the" + "database provider factory. Please check the ProviderName" + "specified in the web.config file."); } }
-
GetDbFactory(string ProviderName)
:返回一个DbProviderFactory
对象。这只是一个重载,以防您希望以编程方式提供ProviderName
。internal static DbProviderFactory GetDbFactory(string ProviderName) { DataTable dtProviders = DbProviderFactories.GetFactoryClasses(); if (dtProviders.Rows.Count == 0) { throw new Exception("No Data Providers are installed in the" + ".Net FrameWork that implement the abstract DbProviderFactory" + "Classes. "); } bool errorFlag = false; foreach (DataRow dr in dtProviders.Rows) { if (dr[2] != null) { string ExistingProviderName = dr[2].ToString(); if (ProviderName.ToLower() == ExistingProviderName.Trim().ToLower()) { errorFlag = false; break; } else { errorFlag = true; } } } if (errorFlag) { throw new Exception("The ProviderName string supplied is not a" + "valid Provider Name or it does not implement the abstract" + "DbProviderFactory Classes. The string ProviderName is" + "case-sensitive. Also please check it for proper spelling. "); } DbProviderFactory Dbfactory = DbProviderFactories.GetFactory(ProviderName); return Dbfactory; }
-
GetConnection()
:返回一个数据库连接对象。这里我们使用上面解释的GetDbFactory()
方法。internal static DbConnection GetConnection() { try { string ConnectionString = Convert.ToString( ConfigurationManager.ConnectionStrings["HPRConnectionString"]); DbProviderFactory Dbfactory = ConnectionClass.GetDbFactory(); DbConnection conn = Dbfactory.CreateConnection(); conn.ConnectionString = ConnectionString; return conn; } catch (DbException) { throw new ApplicationException("An exception has occurred while" + "creating the connection. Please check Connection String settings" + "in the web.config file."); } }
请仔细看,我将所有方法都设置为 internal,以便它们不能从命名空间或数据访问层之外访问。
现在让我们看看 *DbClass.cs* 文件及其方法。
此类为我们在执行任何数据库事务时所需的实用函数集。
下面是屏幕截图。

GetCommand
、GetParameter
、GetParameters
方法都返回相应的 ADO 对象。这些方法使用 `Connection` 类的 `GetDbFactory()` 方法来创建 DbProviderFctory
对象。然后,此对象为我们提供命令、参数、数据读取器等相应的 ADO 对象。
ConnectionClass.GetDbFactory().CreateCommand()
业务层可以利用这些对象并添加其属性,例如 `Parameter` 对象的参数值以及 `Command` 对象的 `commandtype` 和 `commandText`。
还有 `GetTable` 和 `GetDataSet` 等方法,它们接受业务层传入的命令对象并在数据库上执行。想法是,调用应用程序(或函数)需要首先通过调用适当的方法来创建 `Parameter` 和 `Command` 对象。然后,向参数添加值,将参数添加到命令对象,然后根据需要调用 `getTable` 或 `GetDataSet`。
`ExecuteNonQuery` 和 `ExecuteScalar` 方法的工作方式相同,只是它们执行的是更新或插入事务。
*DbClass.cs* 文件中的所有这些方法都使用 *ConnectionClass.cs* 的方法进行连接等。
我还在我的 `DbClass` 方法中使用了 `Transaction` 对象来在事务中执行命令。您可以下载本文上传的 zip 文件,其中包含 *DbClass.cs* 和 *ConnectionClass.cs* 的源代码。
结论
我写这篇文章的目的是帮助用户避免为不同的项目一遍又一遍地编写相同的数据访问代码。
这对于那些实际编写应用程序但不确定生产服务器上会存在什么类型的数据库,或者想象一下客户决定将现有数据库从 SQL 迁移到 Oracle 或 Microsoft Access 的情况非常有帮助。
这些是我作为程序员生活中遇到的一些问题,我希望通过这篇文章能帮助遇到类似问题的人。
反馈
感谢所有阅读我文章的读者,我非常期待您的评论、反馈、建议,以及您可能提供的任何可以改进这篇文章的内容。
编程愉快!