如何编写应用程序,以便只需对其进行很少的改动或不进行改动即可使用数据库服务器 x、y 和 z?”由于知道数据访问层仍然是现代应用程序的最关键部分,通常是经验不足的开发人员的敌人。
我们可以创建专用程序集或共享程序集来封装这些数据访问类,在第一种情况下,程序集加载程序将搜索我们在 ApPBase 文件夹的配置文件内指定的程序集,或者使用典型探测规则在子目录内进行搜索。如果我们必须与其他应用程序共享这些类,则可以将这些程序集置于全局程序集缓存中。
从其他层使用数据访问类
这两个几乎相同的 CustomersData 类包含在应用程序其余部分将使用的两个不同程序集内。通过下面的配置文件,我们现在可以指定要加载的程序集以及面向的数据源。
可能的配置文件示例将类似于如下所示:
<?XML version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="ConnectionString"
value="Server=(local);Database=Northwind;
User ID=UserDemo;Pwd=UserDemo" />
<add key="DALAssembly" value="DALAccess,
version=1.0.0.0, PublicKeyToken=F5CD5666253D6082" />
<!-- <add key="ConnectionString"
value="Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=..\..\..\Northwind.mdb" />
-->
</appSettings>
</configuration> |
我们必须在此文件内指定两条信息。第一条信息是规范的连接字符串(用于为更改提供机会),如服务器名称或其他一些用于连接的参数。第二条信息是程序集的完全限定名,应用程序的上一层将动态加载此程序集以查找与特定数据源一起使用的类:
让我们再来看一下这部分代码:
using System;
using System.Data;
using System.Configuration;
using System.Reflection;
using Common;
namespace BLL
{
public class Customers
{
public DataTable GetAllCustomers()
{
string AssemblyName =
ConfigurationSettings.AppSettings
["DALAssembly"];
string TypeName = "DAL.CustomersData";
IDbCustomers cd =
// (IDbCustomers)=
Assembly.Load(AssemblyName).
CreateInstance(mytype);
DataTable dt = cd.GetCustomers();
return dt;
}
public DataSet GetCustomerOrders()
{
// 待定
return null;
}
}
} |
您可以看到,程序集使用从配置文件中读取的名称进行加载,并创建和使用 CustomersData 类的实例。
一些可能的改进
要了解我所建议的方法的示例,请查看 NET Pet Shop v3.0 示例应用程序。建议您下载此示例并深入了解它,不仅是为了解决可移植性问题,同时也是为了解决其他相关问题(如缓存和性能优化)。
在为可移植应用程序设计数据访问层的过程中,一个需要注意的重要问题是如何与其他层进行信息通信。在本文的示例中,我只使用了一个普通的 DataTable 实例;在生产环境中,您可能希望根据必须表示的数据类型(您必须处理分层结构等)考虑不同的解决方案。在这里,我不希望从头开始,建议您查阅 Designing Data Tier Components and Passing Data Through Tiers 指南,它详细描述了不同情况以及所建议的解决方案的优点。
如我简介中所述,在设计阶段,应该考虑您的目标数据源所公开的特定特性以及总体数据访问。这应该涵盖存储过程、XML 序列化等事项。关于 Microsoft® SQL Server™ 2000,您可以在下面的网址中找到有关如何优化使用这些特性的介绍:.net Data Access Architecture Guide。强烈建议您阅读一下该指南。
我总是收到许多关于 Data Access Application Block 以及它如何与参数关联(如本文所述)的请求。这些 .NET 类充当 SQL Server .NET 数据提供程序之上的抽象层,并使您能够编写更多优秀代码与数据库服务器进行交互。下面是一段演示可行操作的代码:
DataSet ds = SqlHelper.ExecuteDataset(
connectionString,
CommandType.StoredProcedure,
"getProductsByCategory",
new SqlParameter("@CategoryID", categoryID)); |
此方法还有一个外延,您可以在 GotDotNet 上的开放源代码 Data Access Block 3.0 (Abstract Factory Implementation) 示例中找到。此版本实现相同的抽象工厂模式,并使您能够根据可用的 .NET 数据提供程序使用不同数据源。
结论
您现在应能够根据选择的特定数据源构建不需要修改的业务逻辑类,并可以利用给定数据源的唯一特性获得更好的效果。这是有代价的:我们必须实现多组类,以便封装特定数据源的低级别操作,以及可以为每个特定数据源(存储过程、函数等)构建的所有可编程对象。如果希望获得高性能和高可移植性,就必须付出这样的代价。根据我的实际经验,这是完全值得的!