配置数据访问层的连接级和命令级设置71

简介

在本系列教程中,我们一直使用强类型DataSet 来实现分层架构中的数据访问层以及业务对象。我们曾在第一篇教程 中讨论过,强类型 DataSet 的DataTable 用作存储数据的仓库,而 TableAdapter 作为包装与数据库通信,以便检索和修改基础数据。TableAdapter 封装了操作数据库的复杂过程,从而使我们不必编写代码就可以连接数据库、发布命令或将结果填充到DataTable 中。

但有时,我们可能需要深入探索 TableAdapter ,并编写代码直接处理ADO.NET 对象。例如,在教程在事务中封装数据库修改 中,我们向 TableAdapter 添加了用于启动、提交和回滚ADO.NET 事务的方法。这些方法使用一个手动创建的内部SqlTransaction 对象,该对象被分配给TableAdapter 的SqlCommand 对象。

在本教程中,我们将讨论如何在 TableAdapter 中访问数据库的连接级和命令级设置。具体来说,我们将向ProductsTableAdapter 添加功能,从而启用对基础连接字符串和命令超时设置的访问。

使用ADO.NET 处理数据

Microsoft .NET Framework 中包含大量用于处理数据的类。这些类位于 System.Data 命名空间 中,称为 ADO.NET 类。ADO.NET 名下的某些类依赖特定的数据提供程序。我们可以将数据提供程序想象成一个通信渠道,该渠道允许信息在ADO.NET 类和基础数据存储之间流动。这些提供程序中既包含OleDb 和 ODBC 等通用提供程序,也包含专为某个特定数据库系统设计的提供程序。例如,尽管使用OleDb 提供程序可以连接Microsoft SQL Server 数据库,但使用 SqlClient 提供程序的效率更高,因为SqlClient 是专为 SQL Server 设计和优化的。

通过编码访问数据时,通常使用以下模式:

  1. 建立一个数据库连接;
  2. 发布一条命令;
  3. 针对 SELECT 查询处理结果记录。

上述每个步骤都由一个单独的 ADO.NET 类来执行。例如,通过SqlClient 提供程序连接数据库时使用 SqlConnection 类 。而向数据库发布 INSERT 、UPDATE 、DELETE 或 SELECT 命令则使用 SqlCommand 类 。

TableAdapter 自动生成的代码已经包含了用于连接数据库、发布命令、检索数据和向DataTable 填充数据的功能。因此,除了在事务中封装数据库修改教程之外,我们不需要自己编写任何底层ADO.NET 代码。但有时,我们也可能需要自定义这些底层设置。在下面的步骤中,我们将探讨如何设置TableAdapter 内部使用的ADO.NET 对象。

步骤 1:检查 Connection 属性

每个TableAdapter 类都有一个Connection 属性,用于指定数据库连接信息。此属性的数据类型及ConnectionString 的值是由在 TableAdapter Configuration 向导中进行的选择确定的。回顾一下,当我们第一次向强类型DataSet 添加TableAdapter 时,此向导要求我们指定数据库源(参见图1 )。本步骤的下拉列表中包含了配置文件中指定的数据库,以及Server Explorer 的 Data Connections 中的其它数据库。如果我们要使用的数据库未包含在下拉列表中,可以通过单击New Connection 按钮并提供所需的连接信息来指定一个新的数据库连接。

图1 :TableAdapter Configuration Wizard 的第一步

让我们花些时间来检查 TableAdapter 的 Connection 属性的代码。我们在创建数据访问层教程中提到过,要查看自动创建的 TableAdapter 代码,我们可以打开Class View 窗口,进入相应的类,然后双击成员名称。

打开View 菜单并选择 Class View (或按下Ctrl+Shift+C ),导航到 Class View 窗口。从Class View 窗口的上半部分深入到 NorthwindTableAdapters 命名空间,从中选择 ProductsTableAdapter 类。这将在 Class View 的下半部分显示 ProductsTableAdapter 的成员,如图 2 所示。双击 Connection 属性来查看它的代码。

图2 :在 Class View 中双击Connection 属性,查看为该属性自动生成的代码

TableAdapter 的 Connection 属性及其它与连接相关的代码如下所示:

private System.Data.SqlClient.SqlConnection _connection; 
 
private void InitConnection() { 
    this._connection = new System.Data.SqlClient.SqlConnection(); 
    this._connection.ConnectionString =  
        ConfigurationManager.ConnectionStrings["NORTHWNDConnectionString"].ConnectionString; 

 
internal System.Data.SqlClient.SqlConnection Connection { 
    get { 
        if ((this._connection == null)) { 
            this.InitConnection(); 
        } 
        return this._connection; 
    } 
    set { 
        this._connection = value; 
        if ((this.Adapter.InsertCommand != null)) { 
            this.Adapter.InsertCommand.Connection = value; 
        } 
        if ((this.Adapter.DeleteCommand != null)) { 
            this.Adapter.DeleteCommand.Connection = value; 
        } 
        if ((this.Adapter.UpdateCommand != null)) { 
            this.Adapter.UpdateCommand.Connection = value; 
        } 
        for (int i = 0; (i < this.CommandCollection.Length); i = (i + 1)) { 
            if ((this.CommandCollection[i] != null)) { 
                ((System.Data.SqlClient.SqlCommand) 
                    (this.CommandCollection[i])).Connection = value; 
            } 
        } 
    } 
}

当对TableAdapter 类进行实例化时,成员变量 _connection 等于空值。访问 Connection 属性时,首先检查_connection 成员变量是否已被实例化。如果没有,则调用InitConnection 方法,将 _connection 实例化并将其ConnectionString 属性设为在 TableAdapter Configuration 向导的第一步中指定的连接字符串值。

Connection 属性也可分配给SqlConnection 对象,这会将新增 SqlConnection 对象与TableAdapter 的每个SqlCommand 对象关联起来。

步骤2:显示连接级设置

连接信息应封装在 TableAdapter 内,不能被应用程序架构的其它层访问。但有时查询、ASP.NET 页面或用户需要访问或自定义TableAdapter 的连接级信息。

我们将扩展Northwind 数据集中的 ProductsTableAdapter ,使其包含一个 ConnectionString 属性,业务逻辑层可使用该属性读取或更改TableAdapter 使用的连接字符串。

注意 :连接字符串用于指定数据库连接信息 ,如使用的提供程序、数据库的位置、验证凭据及其它数据库相关设置。对于不同数据存储和提供程序使用的连接字符串模式列表,请参考 ConnectionStrings.com 。

正如我们在创建数据访问层 教程中讨论的那样,强类型 DataSet 自动生成的类可通过使用部分类进行扩展。首先,在项目中的~/App_Code/DAL 文件夹下新建一个名为 ConnectionAndCommandSettings 的子文件夹。

图3 :添加一个名为 ConnectionAndCommandSettings 的子文件夹

新增一个名为 ProductsTableAdapter.ConnectionAndCommandSettings.cs 的类文件,并输入以下代码:

using System; 
using System.Data; 
using System.Configuration; 
using System.Web; 
using System.Web.Security; 
using System.Web.UI; 
using System.Web.UI.WebControls; 
using System.Web.UI.WebControls.WebParts; 
using System.Web.UI.HtmlControls; 
 
namespace NorthwindTableAdapters 

    public partial class ProductsTableAdapter 
    { 
        public string ConnectionString 
        { 
            get 
            { 
                return this.Connection.ConnectionString; 
            } 
            set 
            { 
                this.Connection.ConnectionString = value; 
            } 
        } 
    } 
}

部分类向ProductsTableAdapter 类添加一个名为 ConnectionString 的 Public 属性,允许任何层读取或更新 TableAdapter 基础连接的连接字符串。

创建(并保存)此部分类后,打开 ProductsBLL 类。进入一个现有的方法并键入 Adapter ,然后按下句点键打开 IntelliSense 。现在IntelliSense 中会显示新的ConnectionString 属性。这意味着,您可以从 BLL 中通过编码读取或调整此值。

显示整个连接对象

部分类只显示基础连接对象的一个属性,即ConnectionString 。如果想突破TableAdapter 的限制从而访问整个连接对象,我们可以选择更改Connection 属性的保护级别。从步骤1 中的自动生成代码可以看出,TableAdapter 的 Connection 属性标记为internal,即它只能被同一个程序集中的类访问。但我们可以通过TableAdapter 的 ConnectionModifier 属性对此进行更改。

打开Northwind 数据集,在设计器中单击 ProductsTableAdatper ,导航到Properties 窗口。从此窗口中可以看到,ConnectionModifier 设为默认值 Assembly 。要想从强类型 DataSet 程序集的外部访问 Connection 属性,应将ConnectionModifier 属性更改为 Public 。

图4 :Connection 属性的访问级别可通过ConnectionModifier 属性配置

保存数据集,然后返回ProductsBLL 类。与前面的操作一样,进入一个现有的方法并键入Adapter ,然后按下句点键打开IntelliSense 。列表中应包含Connection 属性,即现在可以从 BLL 中通过编码读取或指定连接级的设置了。

步骤3:检查命令相关属性

每个TableAdapter 包含一个主查询。主查询默认包含自动生成的INSERT 、UPDATE 和 DELETE 语句。在TableAdapter 代码中,主查询的INSERT 、UPDATE 和DELETE 语句是通过Adapter 属性作为 ADO.NET 数据适配器对象实现的。与 Connection 属性一样,Adapter 属性的数据类型由使用的数据提供程序确定。由于我们的教程使用SqlClient 提供程序,Adapter 属性为SqlDataAdapter 类型。

TableAdapter 的 Adapter 属性使用如下三个SqlCommand 类型的属性来发布 INSERT 、UPDATE 和 DELETE 语句:

  • InsertCommand
  • UpdateCommand
  • DeleteCommand

SqlCommand 对象负责向数据库发送特定的查询,其属性如下: CommandText ,其中包含要执行的 ad-hoc SQL 语句或存储过程;以及 Parameters ,即 SqlParameter 对象集合。正如我们在创建数据访问层教程中讨论的那样,用户可以通过 Properties 窗口自定义这些命令对象。

除了主查询外,TableAdapter 还可以包含多个方法,这些方法在调用时将向数据库发出具体的命令。主查询的命令对象和所有其它方法的命令对象都存储在TableAdapter 的 CommandCollection 属性中。

让我们花些时间来查看一下 Northwind 数据集中的 ProductsTableAdapter 为上述两个属性及其支持成员变量和 helper 方法生成的代码:

private System.Data.SqlClient.SqlDataAdapter _adapter; 
 
private void InitAdapter() { 
    this._adapter = new System.Data.SqlClient.SqlDataAdapter(); 
     
    ... Code that creates the InsertCommand, UpdateCommand, ... 
    ... and DeleteCommand instances - omitted for brevity ... 

 
private System.Data.SqlClient.SqlDataAdapter Adapter { 
    get { 
        if ((this._adapter == null)) { 
            this.InitAdapter(); 
        } 
        return this._adapter; 
    } 

 
private System.Data.SqlClient.SqlCommand[] _commandCollection; 
 
private void InitCommandCollection() { 
    this._commandCollection = new System.Data.SqlClient.SqlCommand[9]; 
 
    ... Code that creates the command objects for the main query and the ... 
    ... ProductsTableAdapter�s other eight methods - omitted for brevity ... 

 
protected System.Data.SqlClient.SqlCommand[] CommandCollection { 
    get { 
        if ((this._commandCollection == null)) { 
            this.InitCommandCollection(); 
        } 
        return this._commandCollection; 
    } 
}

Adapter 和CommandCollection 属性的代码与 Connection 属性的代码非常相似。有一些成员变量中包含属性使用的对象。属性的Get 访问器启动时检查相应成员变量是否为空值。如果是,则调用一个初始化方法,创建成员变量的一个实例,并为核心的命令相关属性赋值。

步骤4:显示命令级设置

在理想情况下,命令级信息应封装在数据访问层中。但如果架构中的其它层需要使用这些信息,则可通过部分类来显示,如同显示连接级设置一样。

由于TableAdapter 只有一个Connection 属性,用于显示连接级设置的代码非常简单。但更改命令级设置则较为复杂。因为TableAdapter 可能有多个命令对象(InsertCommand 、UpdateCommand 和 DeleteCommand )以及 CommandCollection 属性包含的数量不定的命令对象。更新命令级设置时,需要将这些设置传送给所有命令对象。

例如,假设 TableAdapter 中某些查询的执行相当耗时,当使用 TableAdapter 执行其中某个查询时,我们可能希望增大命令对象的CommandTimeout 属性 的值。此属性指定该命令执行时的等待时间,默认值为30 秒。

要允许通过 BLL 更改 CommandTimeout 属性,使用步骤 2 中创建的部分类文件 (ProductsTableAdapter.ConnectionAndCommandSettings.cs) 向 ProductsDataTable 添加以下 Public 方法即可 :

public void SetCommandTimeout(int timeout) 

    if (this.Adapter.InsertCommand != null) 
        this.Adapter.InsertCommand.CommandTimeout = timeout; 
 
    if (this.Adapter.DeleteCommand != null) 
        this.Adapter.DeleteCommand.CommandTimeout = timeout; 
 
    if (this.Adapter.UpdateCommand != null) 
        this.Adapter.UpdateCommand.CommandTimeout = timeout; 
 
    for (int i = 0; i < this.CommandCollection.Length; i++) 
        if (this.CommandCollection[i] != null) 
            this.CommandCollection[i].CommandTimeout = timeout; 
}

此方法可从 BLL 或表示层调用,用于设置 TableAdapter 实例发布的所有命令的超时时间。

注意 :Adapter 和 CommandCollection 属性标记为 Private ,这表示它们只能从 TableAdapter 中的代码访问。与 Connection 属性不同,这些访问修饰符是不可配置的。因此,如果需要向架构中的其它层显示命令级属性,必须使用前面提到的部分类方法提供一个Public 方法或属性,利用该方法或属性对 Private 命令对象执行读取或写入操作。

小结

强类型DataSet 中的 TableAdapter 用于封装数据访问的详细信息和复杂性。通过TableAdapter ,我们无需编写ADO.NET 代码便可连接数据库、发布命令或使用结果填充DataTable 。这些都是自动完成的。

但有时,我们需要自定义底层 ADO.NET 的细节,如更改连接字符串、默认连接或命令超时设置。TableAdapter 自动生成 Connection 、Adapter 和 CommandCollection 属性。但这些属性都默认为 internal 或private 。要显示内部信息,我们可以使用部分类扩展TableAdapter ,使其包含 public 方法或属性即可。TableAdapter 的 Connection 属性访问修饰符也可通过TableAdapter 的ConnectionModifier 属性配置。

快乐编程!

posted @ 2016-05-02 00:38  迅捷之风  阅读(189)  评论(0编辑  收藏  举报