配置数据访问层的连接和命令级别的设置 (C#)
Typed DataSet 中的 TableAdapters 会自动负责连接到数据库、发出命令以及使用结果填充 DataTable。 但是,有时我们需要自行处理这些详细信息,在本教程中,我们将了解如何访问 TableAdapter 中的数据库连接和命令级设置。
简介
在整个教程系列中,我们使用了类型化数据集来实现分层体系结构的数据访问层和业务对象。 如 第一篇教程中所述,Typed DataSet 的 DataTable 充当数据的存储库,而 TableAdapter 充当包装器,用于与数据库通信以检索和修改基础数据。 TableAdapters 封装了使用数据库所涉及的复杂性,使我们不必编写代码来连接到数据库、发出命令或将结果填充到 DataTable 中。
但是,有时我们需要钻取到 TableAdapter 的深度,并编写直接处理 ADO.NET 对象的代码。 例如,在 事务内包装数据库修改 教程中,我们向 TableAdapter 添加了用于开始、提交和回滚 ADO.NET 事务的方法。 这些方法使用了分配给 TableAdapter 对象的SqlCommand
手动创建SqlTransaction
的内部对象。
本教程介绍如何访问 TableAdapter 中的数据库连接和命令级设置。 具体而言,我们将向 添加允许访问基础连接字符串和命令超时设置的功能ProductsTableAdapter
。
使用 ADO.NET 处理数据
Microsoft .NET Framework包含大量专为处理数据而设计的类。 这些类位于 命名空间中System.Data
,称为 ADO.NET 类。 ADO.NET 保护伞下的某些类与特定 数据提供程序相关联。 可以将数据提供程序视为允许信息在 ADO.NET 类和基础数据存储之间流动的信道。 有通用的提供程序(如 OleDb 和 ODBC),以及专为特定数据库系统设计的提供程序。 例如,虽然可以使用 OleDb 提供程序连接到 Microsoft SQL Server 数据库,但 SqlClient 提供程序的效率要高得多,因为它专为SQL Server而设计和优化。
以编程方式访问数据时,通常使用以下模式:
- 建立与数据库的连接。
- 发出命令。
- 对于
SELECT
查询,请使用生成的记录。
有单独的 ADO.NET 类用于执行上述每个步骤。 例如,若要使用 SqlClient 提供程序连接到数据库,请使用 SqlConnection
类。 若要向 INSERT
数据库发出 、 UPDATE
、 DELETE
或 SELECT
命令,请使用 SqlCommand
类。
除了 在事务中包装数据库修改 教程外,我们不必自行编写任何低级别 ADO.NET 代码,因为 TableAdapters 自动生成的代码包括连接到数据库、发出命令、检索数据以及将数据填充到 DataTables 所需的功能。 但是,有时可能需要自定义这些低级别设置。 在接下来的几个步骤中,我们将了解如何利用 TableAdapters 在内部使用的 ADO.NET 对象。
步骤 1:使用连接属性检查
每个 TableAdapter 类都有一个 Connection
指定数据库连接信息的属性。 此属性的数据类型和 ConnectionString
值由 TableAdapter 配置向导中的选择确定。 回想一下,当我们第一次将 TableAdapter 添加到 Typed DataSet 时,此向导会要求我们输入数据库源 (请参阅图 1) 。 第一步中的下拉列表包括配置文件中指定的数据库以及服务器资源管理器数据Connections中的任何其他数据库。 如果下拉列表中不存在要使用的数据库,可以通过单击“新建连接”按钮并提供所需的连接信息来指定新的数据库连接。
图 1:TableAdapter 配置向导的第一步 (单击以查看全尺寸映像)
让我们花点时间检查 TableAdapter s 属性的代码 Connection
。 如 创建数据访问层 教程中所述,我们可以通过转到“类视图”窗口,向下钻取到相应的类,然后双击成员名称来查看自动生成的 TableAdapter 代码。
转到“视图”菜单并选择“类视图” (或通过键入 Ctrl+Shift+C) 导航到“类视图”窗口。 从“类视图”窗口的上半部分,向下钻取到 NorthwindTableAdapters
命名空间并选择类 ProductsTableAdapter
。 这将在 ProductsTableAdapter
类视图的下半部分显示成员,如图 2 所示。 双击 属性 Connection
以查看其代码。
图 2:在类视图中 Double-Click 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
等于 null
。 Connection
访问 属性时,它首先检查成员变量是否已_connection
实例化。 如果没有,InitConnection
则调用 方法,这将实例化_connection
其ConnectionString
属性并将其设置为从 TableAdapter 配置向导的第一步指定的连接字符串值。
还可以 Connection
将 属性分配给 SqlConnection
对象。 这样做会将新 SqlConnection
对象与每个 TableAdapter 对象 SqlCommand
相关联。
步骤 2:公开 Connection-Level 设置
连接信息应仍封装在 TableAdapter 中,应用程序体系结构中的其他层无法访问。 但是,在某些情况下,可能需要为查询、用户或 ASP.NET 页面访问或自定义 TableAdapter 的连接级别信息。
让我们扩展 ProductsTableAdapter
DataSet 中的 Northwind
,以包含一个ConnectionString
属性,业务逻辑层可以使用该属性来读取或更改 TableAdapter 使用的连接字符串。
注意
连接字符串是一个字符串,用于指定数据库连接信息,例如要使用的提供程序、数据库的位置、身份验证凭据和其他与数据库相关的设置。 有关各种数据存储和提供程序使用的连接字符串模式的列表,请参阅 ConnectionStrings.com。
如 创建数据访问层 教程中所述,可以通过使用分部类扩展类型化数据集自动生成的类。 首先,在文件夹下~/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;
}
}
}
}
此分部类将名为 ConnectionString
的属性添加到 public
类中ProductsTableAdapter
,该类允许任何层读取或更新 TableAdapter 基础连接的连接字符串。
(创建分部类并保存) ,打开 类 ProductsBLL
。 转到现有方法之一并键入 , Adapter
然后按句点键来启动 IntelliSense。 应会看到 IntelliSense 中提供的新 ConnectionString
属性,这意味着可以通过编程方式从 BLL 读取或调整此值。
公开整个连接对象
此分部类仅公开基础连接对象的一个属性: ConnectionString
。 如果要使整个连接对象超出 TableAdapter 的范围,也可以更改 Connection
属性的保护级别。 我们在步骤 1 中检查的自动生成的代码显示 TableAdapter 的 Connection
属性被标记为 internal
,这意味着它只能由同一程序集中的类访问。 但是,可以通过 TableAdapter 属性 ConnectionModifier
更改此值。
打开Northwind
数据集,单击ProductsTableAdapter
Designer中的 ,然后导航到属性窗口。 在那里, ConnectionModifier
你将看到 设置为其默认值 Assembly
。 若要使 Connection
属性在 Typed DataSet 程序集之外可用,请将 ConnectionModifier
属性更改为 Public
。
图 4: Connection
可以通过 属性配置 ConnectionModifier
属性辅助功能级别 (单击以查看全尺寸图像)
保存 DataSet,然后返回到 ProductsBLL
类。 与以前一样,转到现有方法之一并键入 , Adapter
然后按句点键来启动 IntelliSense。 该列表应包含属性 Connection
,这意味着你现在可以以编程方式从 BLL 读取或分配任何连接级别设置。
步骤 3:检查 Command-Related 属性
TableAdapter 由main查询组成,默认情况下,查询具有自动生成的 INSERT
、 UPDATE
和 DELETE
语句。 此main查询 INSERT
、 UPDATE
和 DELETE
语句通过 Adapter
属性作为 ADO.NET 数据适配器对象在 TableAdapter 代码中实现。 与属性 Connection
一样, Adapter
属性的数据类型由使用的数据提供程序确定。 由于这些教程使用 SqlClient 提供程序,因此 属性 Adapter
的类型 SqlDataAdapter
为 。
TableAdapter 属性 Adapter
具有三个类型的 SqlCommand
属性,用于发出 INSERT
、 UPDATE
和 DELETE
语句:
InsertCommand
UpdateCommand
DeleteCommand
SqlCommand
对象负责将特定查询发送到数据库,并具有以下属性:CommandText
,其中包含要执行的即席 SQL 语句或存储过程;和 Parameters
,它是对象的集合SqlParameter
。 正如我们在创建数据访问层教程中看到的那样,可以通过属性窗口自定义这些命令对象。
除了其main查询之外,TableAdapter 还可以包含数量可变的方法,在调用时,这些方法会向数据库调度指定的命令。 main查询 命令对象和所有其他方法的命令对象存储在 TableAdapter 的 CommandCollection
属性中。
让我们花点时间看看 DataSet 中Northwind
为这两个属性及其支持成员变量和帮助程序方法生成的ProductsTableAdapter
代码:
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
非常模仿 属性的代码Connection
。CommandCollection
有一些成员变量用于保存属性使用的对象。 属性 get
访问器首先检查相应的成员变量是否为 null
。 如果是,则调用初始化方法,该方法创建成员变量的实例并分配与命令相关的核心属性。
步骤 4:公开 Command-Level 设置
理想情况下,命令级信息应保持封装在数据访问层中。 但是,如果体系结构的其他层需要此信息,可以通过分部类公开此信息,就像使用连接级设置一样。
由于 TableAdapter 只有一 Connection
个属性,因此用于公开连接级别设置的代码相当简单。 修改命令级设置时,事情会稍微复杂一些,因为 TableAdapter 可以有多个命令对象 - 一个 InsertCommand
、 UpdateCommand
和 DeleteCommand
,以及 属性中 CommandCollection
可变数量的命令对象。 更新命令级设置时,需要将这些设置传播到所有命令对象。
例如,假设 TableAdapter 中有某些查询执行时间过长。 使用 TableAdapter 执行其中一个查询时,我们可能需要增加命令对象的 属性CommandTimeout
。 此属性指定等待命令执行的秒数,默认值为 30。
若要允许 CommandTimeout
BLL 调整 属性,请使用步骤 2 ProductsTableAdapter.ConnectionAndCommandSettings.cs
() 中创建的分部类文件将以下public
方法ProductsDataTable
添加到 :
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
命令对象的方法或属性。
总结
类型化数据集中的 TableAdapter 用于封装数据访问详细信息和复杂性。 使用 TableAdapter,我们不必担心编写 ADO.NET 代码以连接到数据库、发出命令或将结果填充到 DataTable 中。 这一切都会自动为我们处理。
但是,有时我们可能需要自定义低级别 ADO.NET 细节,例如更改连接字符串、默认连接或命令超时值。 TableAdapter 具有自动生成的 Connection
、 Adapter
和 CommandCollection
属性,但这些属性默认为 internal
或 private
。 可以通过使用分部类扩展 TableAdapter 以包括 public
方法或属性来公开此内部信息。 或者,可以通过 TableAdapter 属性 Connection
配置 TableAdapter 属性 ConnectionModifier
访问修饰符。
编程愉快!
关于作者
Scott Mitchell 是七本 ASP/ASP.NET 书籍的作者, 4GuysFromRolla.com 的创始人,自 1998 年以来一直从事 Microsoft Web 技术工作。 Scott 担任独立顾问、培训师和作家。 他的最新书是 山姆斯在24小时内 ASP.NET 2.0自学。 可以在 上联系 mitchell@4GuysFromRolla.com他, 也可以通过他的博客联系到他,该博客可在 http://ScottOnWriting.NET中找到。
特别感谢
本教程系列由许多有用的审阅者查看。 本教程的主要审阅者是 Burnadette Leigh、S ren Jacob Lauritsen、Teresa Murphy 和 Hilton Geisenow。 有兴趣查看我即将发布的 MSDN 文章? 如果是,请在 处放置一行 mitchell@4GuysFromRolla.com。