数据适配器定义一些方法,您可以使用这些方法将数据源中的一个或多个表内的信息送入数据集并再从数据集取回这些信息。

在 Visual Studio 中,创建和配置数据适配器有多种方法:使用“服务器资源管理器”、向导、“手动”(用“属性”窗口配置)和使用代码。下面列出的主题提供有关各种方法的信息。

本节内容

使用“服务器资源管理器”创建数据适配器':解释如何将数据库元素拖动到窗体或组件上并自动生成适配器。

本过程描述从“服务器资源管理器”创建数据适配器。通常,在创建适配器之后希望对其进行一些配置更改。

使用“服务器资源管理器”创建数据适配器

  1. 在适当的设计器中打开窗体或组件,然后打开“服务器资源管理器”。有关详细信息,请参阅 访问和初始化服务器资源管理器
  2. 如果所需连接尚不存在,则创建该连接。有关详细信息,请参阅 在服务器资源管理器中添加新的数据连接
  3. 打开连接节点,然后展开任意元素节点(“表”、“存储过程”、“视图”或“函数”)。如果打算使用表,则展开表名节点以显式表列。
    注意 如果打算使用存储过程,则需要在创建适配器以后手动配置它的 UpdateCommandInsertCommandDeleteCommand 属性。
  4. 选择一列或多列(在“表”下)或某存储过程,然后将选定内容拖动到设计器上。
    注意 可以将表名拖动到设计器上来替代选择和拖动单个列。这样做将产生一个 SQL SELECT * FROM tablename 查询。选择单个列通常更有效,因为限制了数据库和数据集之间传输的数据量。

    在将选定内容放到设计器以后,Visual Studio 将为该数据源创建连接对象的一个实例(如果尚没有的话)和一个数据适配器对象。

    如果将表或单个列拖动到设计器上,则配置适配器以便读取和更新数据。如果将存储过程拖动到设计器上,则配置适配器以便读取数据。

  5. 如果想要查看数据适配器填充数据集的方式,请预览结果。

从“服务器资源管理器”拖动数据元素很容易,但不为您提供创建参数化查询或创建新的存储过程来访问数据的机会。为获得该机会,可以使用“数据适配器配置向导”。

使用向导创建数据适配器:解释“数据适配器配置向导”如何提示您输入配置数据适配器以及创建连接(如果必要)所需的所有信息(包括参数)。

“数据适配器配置向导”提供创建数据适配器的最简单和最灵活的方法。有关详细信息,请参阅 数据适配器配置向导

使用“数据适配器配置向导”创建数据适配器

  1. 在适当的设计器中打开要创建的窗体或组件。
  2. 从“工具箱”的“数据”选项卡将一个 OleDbDataAdapterSqlDataAdapter 对象拖动到设计图面上。

    设计器将向窗体或组件添加适配器的一个实例,并启动“数据适配器配置向导”。

  3. 在该向导中,执行下列操作:
    1. 在第二页中,创建或选择一个连接。
    2. 在第三页中,指定适配器应使用 SQL 语句还是存储过程读写数据。选择下表中列出的选项之一。
      选项 说明
      使用 SQL 语句 将定义一条 SQL SELECT 语句,适配器将使用该语句填充数据集内的表。根据 SELECT 语句,向导还将生成 UPDATE、INSERT 和 DELETE 语句以更新数据源。
      使用新创建的存储过程 指定一条 SELECT 语句,向导从该语句创建存储过程以读取和更新数据源。如果提供程序不支持该选项,则它变灰。
      使用现有存储过程 将指定现有存储过程,适配器将使用这些过程读取和更新数据源。

      您所做的选择决定下面窗格上的显示内容。

    3. 在第四页中,创建 SELECT 语句或选择现有存储过程。为了有助于生成 SQL 语句,请单击“SQL 生成器”以启动“查询生成器”。
      注意 可以创建 WHERE 子句中有参数占位符的查询,该参数占位符将以运行时收集的信息填充。

    在完成向导后,它将用您在第二页中指定的信息生成连接对象的一个实例。

  4. 如果想要更改适配器和连接的名称,请分别在设计器中选择它们,并在“属性”窗口中为它们分别提供新名称。
  5. 如果想要查看适配器将填写到数据集的数据,可以进行预览。

还可以手动创建和配置适配器。若要这样做,必须已有一个可用的连接对象。配置数据适配器的部分操作涉及建立数据源和数据集内的表之间的表映射。

手动创建和配置数据适配器:解释如何从“工具箱”拖动数据适配器,然后使用“属性”窗口自行对其进行配置。

可以“手动”创建数据适配器(即不使用向导)。无论创建适配器的方式如何,总可以对它进行配置更改。

手动创建数据适配器

  1. 确保正在操作的窗体或组件有可用的连接对象。
  2. 从“工具箱”的“数据”选项卡将一个 OleDbDataAdapterSqlDataAdapter 对象拖动到设计图面上。

    设计器将向窗体或组件添加适配器的一个实例,并启动“数据适配器配置向导”。

  3. 关闭向导。

手动配置数据适配器

  1. 选择适配器,然后在“属性”窗口中配置用于读取和更新数据的命令。必须配置 SelectCommand 对象。如果适配器将用于更新数据源,则还必须配置 UpdateCommandDeleteCommandInsertCommand 对象。

    为每个命令对象设置下列属性。

属性 说明
ActiveConnection 设置以引用连接对象。可以在“属性”窗口中从 ActiveConnection 属性创建连接对象。通常,每个命令对象将引用相同的连接对象,但如果应用程序需要,可以选择每个命令使用不同的连接。
CommandText SQL 语句的文本或存储过程的名称。

对于某些提供程序,可以在 CommandText 属性中包含多个语句或存储过程名称,以分号 (;) 分隔。这些语句或存储过程按顺序执行。这在类似下面的情况下很有用:在更新或 INSERT 语句之后发出一条 SELECT 语句以取回已刷新记录和任何自动生成的值(如默认值或自动增加的值)。

并非所有提供程序都支持该功能。

CommandType 一个值,该值指示应怎样解释 CommandText 属性的值:
  • Text - 该命令是一条 SQL 语句。
  • StoredProcedure - 该命令是对某存储过程的引用。
  • TableDirect - 该文本不是命令,而是某个表的名称。
Parameters Parameter 类型的对象的集合,配置这些对象以向命令传递值。在 SelectCommand 对象中,仅当命令包含参数占位符时才创建参数集合。UpdateCommandInsertCommandDeleteCommand 对象总需要参数。
  1. 如果不希望数据源和数据集内的列名相同,请更改映射。MissingMappingAction 属性的默认值 (Passthrough) 将自动在数据源和数据集内生成相同名称。
  2. 从“数据”菜单中选择“生成数据集”。
    提示 如果未看到“数据”菜单,请单击窗体或组件设计器中的任意位置;仅当设计器具有焦点时该菜单才出现。
  3. 如果想要查看数据适配器填充数据集的方式,请预览结果。

从 DataAdapter 填充 DataSet:解释如何通过代码创建适配器的实例并使用它来填充数据集。

ADO.NET DataSet 是数据的内存驻留表示形式,它提供了独立于数据源的一致关系编程模型。DataSet 表示整个数据集,其中包含表、约束和表之间的关系。由于 DataSet 独立于数据源,DataSet 可以包含应用程序本地的数据,也可以包含来自多个数据源的数据。与现有数据源的交互通过 DataAdapter 来控制。

随 .NET 框架提供的每个 .NET 数据提供程序都包含一个 DataAdapter 对象:OLE DB .NET 数据提供程序包含一个 OleDbDataAdapter 对象,而 SQL Server .NET 数据提供程序包含一个 SqlDataAdapter 对象。DataAdapter 对象用于从数据源中检索数据并填充 DataSet 中的表。DataAdapter 还会将对 DataSet 作出的更改解析回数据源。DataAdapter 使用 .NET 数据提供程序的 Connection 来连接到数据源,使用 Command 对象从数据源中检索数据并将更改解析回数据源。

DataAdapterSelectCommand 属性是一个 Command 对象,它从数据源中检索数据。DataAdapterInsertCommandUpdateCommandDeleteCommand 属性也是 Command 对象,它们按照对 DataSet 中数据的修改来管理对数据源中数据的更新。这些属性将在使用 DataAdapter 和 DataSet 更新数据库中详细介绍。

DataAdapterFill 方法用于使用 DataAdapterSelectCommand 的结果来填充 DataSetFill 将要填充的 DataSetDataTable 对象(或要使用从 SelectCommand 中返回的行来填充的 DataTable 的名称)用作它的参数。

Fill 方法使用 DataReader 对象来隐式地返回用于在 DataSet 中创建表的列名称和类型以及用来填充 DataSet 中的表行的数据。表和列仅在不存在时才创建;否则,Fill 将使用现有的 DataSet 架构。列类型按照将 .NET 数据提供程序数据类型映射到 .NET 框架数据类型中的表创建为 .NET 框架类型。除非数据源中存在主键并且 DataAdapter.MissingSchemaAction 设置为 MissingSchemaAction.AddWithKey,否则不会创建主键。如果 Fill 发现存在用于某表的主键,那么对于其中的主键列值与从数据源中返回的行的主键值相匹配的行,它将使用数据源中的数据改写 DataSet 中的数据。如果未找到任何主键,则数据将追加到 DataSet 中的表。当填充 DataSet 时,Fill 会使用任何可能存在的 TableMappings(请参阅设置 DataTable 和 DataColumn 映射)。

以下代码示例创建 DataAdapter 的一个实例,该实例使用与 Microsoft SQL Server Northwind 数据库的 Connection 并使用客户列表来填充 DataSet 中的 DataTable。向 DataAdapter 构造函数传递的SQL 语句和 Connection 参数用于创建 DataAdapterSelectCommand 属性。

SqlClient

Dim nwindConn As SqlConnection = New SqlConnection("Data Source=
localhost;Integrated Security=SSPI;Initial Catalog=northwind")

Dim selectCMD As SqlCommand = New SqlCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn)
selectCMD.CommandTimeout = 30

Dim custDA As SqlDataAdapter = New SqlDataAdapter
custDA.SelectCommand = selectCMD

nwindConn.Open()

Dim custDS As DataSet = New DataSet
custDA.Fill(custDS, "Customers")

nwindConn.Close()

SqlConnection nwindConn = new SqlConnection("Data Source=localhost;
Integrated Security=SSPI;Initial Catalog=northwind");

SqlCommand selectCMD = new SqlCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn);
selectCMD.CommandTimeout = 30;

SqlDataAdapter custDA = new SqlDataAdapter();
custDA.SelectCommand = selectCMD;

nwindConn.Open();

DataSet custDS = new DataSet();
custDA.Fill(custDS, "Customers");

nwindConn.Close();

OleDb

Dim nwindConn As OleDbConnection = New OleDbConnection("Provider=SQLOLEDB;Data 
Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind")

Dim selectCMD As OleDbCommand = New OleDbCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn)
selectCMD.CommandTimeout = 30

Dim custDA As OleDbDataAdapter = New OleDbDataAdapter
custDA.SelectCommand = selectCMD

Dim custDS As DataSet = New DataSet
custDA.Fill(custDS, "Customers")

OleDbConnection nwindConn = new OleDbConnection("Provider=SQLOLEDB;Data 
Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind");

OleDbCommand selectCMD = new OleDbCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn);
selectCMD.CommandTimeout = 30;

OleDbDataAdapter custDA = new OleDbDataAdapter();
custDA.SelectCommand = selectCMD;

DataSet custDS = new DataSet();
custDA.Fill(custDS, "Customers");

请注意,该代码不显式打开和关闭 Connection。如果 Fill 方法发现连接尚未打开,它将隐式地打开 DataAdapter 正在使用的 Connection。如果 Fill 已打开连接,它还将在 Fill 完成时关闭连接。当处理单一操作(如 FillUpdate)时,这可以简化您的代码。但是,如果您在执行多项需要打开连接的操作,则可以通过以下方式提高应用程序的性能:显式调用 ConnectionOpen 方法,对数据源执行操作,然后调用 ConnectionClose 方法。为了释放资源供其他客户端应用程序使用,应设法使与数据源的连接打开尽可能短的时间。

多个结果集

如果 DataAdapter 遇到多个结果集,它将在 DataSet 中创建多个表。将向这些表提供递增的默认名称 TableN,以表示 Table0 的“Table”为第一个表名。如果以参数形式向 Fill 方法传递表名称,则将向这些表提供递增的默认名称 TableNameN,这些表名称以表示 TableName0 的“TableName”为起始。

从多个 DataAdapter 填充 DataSet

可以将任意数量的 DataAdapter 与一个 DataSet 一起使用。每个 DataAdapter 都可用于填充一个或多个 DataTable 对象并将更新解析回相关数据源。DataRelationConstraint 对象可以在本地添加到 DataSet,这样,您就可以使来自多个不同数据源的数据相关联。例如,DataSet 可以包含来自 Microsoft SQL Server 数据库、通过 OLE DB 公开的 IBM DB2 数据库以及对 XML 进行流处理的数据源的数据。一个或多个 DataAdapter 对象可以处理与每个数据源的通讯。

以下代码示例从 Microsoft SQL Server 2000 上的 Northwind 数据库填充客户列表,从存储在 Microsoft® Access 2000 中的 Northwind 数据库填充订单列表。已填充的表通过 DataRelation 相关联,然后客户列表将与相应客户的订单一起显示出来。

Dim custConn As SqlConnection= New SqlConnection("Data Source=localhost;Integrated 
Security=SSPI;Initial Catalog=northwind;")
Dim custDA As SqlDataAdapter = New SqlDataAdapter("SELECT * FROM Customers", custConn)

Dim orderConn As OleDbConnection = New OleDbConnection("Provider=Microsoft.Jet.
OLEDB.4.0;Data Source=c:\Program Files\Microsoft Office\" & _
                                                       "Office\Samples\northwind.mdb;")
Dim orderDA As OleDbDataAdapter = New OleDbDataAdapter("SELECT * FROM Orders", orderConn)

custConn.Open()
orderConn.Open()

Dim custDS As DataSet = New DataSet()

custDA.Fill(custDS, "Customers")
orderDA.Fill(custDS, "Orders")

custConn.Close()
orderConn.Close()

Dim custOrderRel As DataRelation = custDS.Relations.Add("CustOrders", _
                                     custDS.Tables("Customers").Columns("CustomerID"), _ 
                                     custDS.Tables("Orders").Columns("CustomerID"))

Dim pRow, cRow As DataRow

For Each pRow In custDS.Tables("Customers").Rows
  Console.WriteLine(pRow("CustomerID").ToString())

  For Each cRow In pRow.GetChildRows(custOrderRel)
    Console.WriteLine(vbTab & cRow("OrderID").ToString())
  Next
Next

SqlConnection custConn = new SqlConnection("Data Source=localhost;Integrated 
Security=SSPI;Initial Catalog=northwind;");
SqlDataAdapter custDA = new SqlDataAdapter("SELECT * FROM Customers", custConn);

OleDbConnection orderConn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=c:\\Program Files\\Microsoft Office\\Office\\Samples\\northwind.mdb;");
OleDbDataAdapter orderDA = new OleDbDataAdapter("SELECT * FROM Orders", orderConn);

custConn.Open();
orderConn.Open();

DataSet custDS = new DataSet();

custDA.Fill(custDS, "Customers");
orderDA.Fill(custDS, "Orders");

custConn.Close();
orderConn.Close();

DataRelation custOrderRel = custDS.Relations.Add("CustOrders",
                              custDS.Tables["Customers"].Columns["CustomerID"],    
                              custDS.Tables["Orders"].Columns["CustomerID"]);

foreach (DataRow pRow in custDS.Tables["Customers"].Rows)
{
  Console.WriteLine(pRow["CustomerID"]);
   foreach (DataRow cRow in pRow.GetChildRows(custOrderRel))
    Console.WriteLine("\t" + cRow["OrderID"]);
}

SQL Server Decimal 类型

DataSet 使用 .NET 框架数据类型来存储数据。对于大多数应用程序,这些类型都提供了一种方便的数据源信息表示形式。但是,当数据源中的数据类型是 SQL Server decimal 时,这种表示形式可能会导致问题。.NET 框架 decimal 数据类型最多允许 28 个有效位,而 SQL Server decimal 数据类型则允许 38 个有效位。如果 SqlDataAdapterFill 操作过程中确定 SQL Server decimal 字段的精度大于 28 个字符,则当前行将不会被添加到 DataTable 中。此时将发生 FillError 事件,它使您能够确定是否将发生精度损失并作出适当的响应。若要获取 SQL Server decimal 值,还可以使用 SqlDataReader 对象并调用 GetSqlDecimal 方法。

OLE DB 章节

分层行集或章节(OLE DB 类型 DBTYPE_HCHAPTER、ADO 类型 adChapter)可用于填充 DataSet 的内容。当 DataAdapterFill 操作过程中遇到章节列时,将为章节列创建一个 DataTable,并使用章节中的列和行填充该表。为章节列创建的表使用父表名称和章节列名称来命名,其形式为“ParentTableNameChapteredColumnName”。如果 DataSet 中已存在与章节列的名称相匹配的表,则将使用章节数据填充当前表。如果现有表中不存在与章节中的列相匹配的列,则将添加新列。

在使用章节列中的数据填充 DataSet 中的表之前,将创建分层行集的父表和子表之间的关系,方法是向父表和子表添加一个整数列,将父列设置为自动递增,然后使用两个表中所添加的列来创建 DataRelation。所添加的关系使用父列名和子列名来命名,其形式为“ParentColumnName_ChildColumnName”。

请注意,相关列仅存在于 DataSet 中。如果在随后从数据源进行填充,则将使新行被添加到表中,而不是使更改被并入现有行。

另请注意,如果使用采用 DataTableDataAdapter.Fill 重载,则将只填充该表。仍会将自动递增整数列添加到该表中,但不会创建或填充任何子表并且不会创建任何关系。

以下示例使用 MSDataShape 提供程序为客户列表中的每个客户生成订单的章节列。然后使用相应数据来填充 DataSet

Dim nwindConn As OleDbConnection = New OleDbConnection("Provider=MSDataShape;
Data Provider=SQLOLEDB;Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind")

Dim custDA As OleDbDataAdapter = New OleDbDataAdapter("SHAPE {SELECT CustomerID, 
CompanyName FROM Customers} APPEND ({SELECT CustomerID, OrderID FROM 
Orders} AS Orders RELATE CustomerID TO CustomerID)", nwindConn)

Dim custDS As DataSet = New DataSet()

custDA.Fill(custDS, "Customers")

OleDbConnection nwindConn = new OleDbConnection("Provider=MSDataShape;
Data Provider=SQLOLEDB;Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind");

OleDbDataAdapter custDA = new OleDbDataAdapter("SHAPE {SELECT 
CustomerID, CompanyName FROM Customers} APPEND ({SELECT CustomerID,
 OrderID FROM Orders} AS Orders  RELATE CustomerID TO CustomerID)", nwindConn);

DataSet custDS = new DataSet();
custDA.Fill(custDS, "Customers");

Fill 操作完成时,DataSet 将包含两个表:CustomersCustomersOrders,其中 CustomersOrders 表示章节列。一个名为 Orders 的附加列被添加到 Customers 表中,一个名为 CustomersOrders 的附加列被添加到 CustomersOrders 表中。Customers 表中的 Orders 列设置为自动递增。DataRelation Orders_CustomersOrders 使用已添加到以 Customers 为父表的表中的列来创建。下表显示了一些示例结果。

表名称:Customers

CustomerID CompanyName Orders
ALFKI Alfreds Futterkiste 0
ANATR Ana Trujillo Emparedados y helados 1

表名称:CustomerOrders

CustomerID OrderID CustomersOrders
ALFKI 10643 0
ALFKI 10692 0
ANATR 10308 1
ANATR 10625 1