从 DataAdapter 填充数据集

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

SelectCommandDataAdapter 属性是一个 Command 对象,用于从数据源中检索数据。 InsertCommandUpdateCommandDeleteCommandDataAdapter 属性是 Command 对象,用于按照对 DataSet中数据的修改来管理对数据源中数据的更新。 使用 DataAdapters 更新数据源中更详细地介绍了这些属性。

FillDataAdapter 方法用于使用 DataSetSelectCommand 结果填充 DataAdapterFill 将要填充的 DataSet 、和 DataTable 对象(或要使用从 DataTable 中返回的行来填充的 SelectCommand的名称)作为它的参数。

备注

使用 DataAdapter 检索表的全部内容会花费些时间,尤其是在表中有很多行时。 这是因为访问数据库,定位和处理数据,然后将数据传输到客户端是需要很长时间的。 将表中全部内容提取到客户端还会在服务器上锁定所有行。 若要提高性能,您可以使用 WHERE 子句使返回客户端的行数大为减少。 还可以通过只显式列出 SELECT 语句要求的列减少返回到客户端的数据量。 另一种好的变通方法是以批次检索行(例如一次检索几百行),并且在客户端完成当前批次后只检索下一批次。

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

备注

如果 SelectCommand 返回 OUTER JOIN 的结果,则 DataAdapter 不会为生成的 PrimaryKey 设置 DataTable值。 您必须自己定义 PrimaryKey 以确保正确解析重复行。 有关详细信息,请参阅定义主键

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

示例

' Assumes that connection is a valid SqlConnection object.  
Dim queryString As String = _  
  "SELECT CustomerID, CompanyName FROM dbo.Customers"  
Dim adapter As SqlDataAdapter = New SqlDataAdapter( _  
  queryString, connection)  
  
Dim customers As DataSet = New DataSet  
adapter.Fill(customers, "Customers")  
// Assumes that connection is a valid SqlConnection object.  
string queryString =
  "SELECT CustomerID, CompanyName FROM dbo.Customers";  
SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);  
  
DataSet customers = new DataSet();  
adapter.Fill(customers, "Customers");  

注意

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

多个结果集

如果 DataAdapter 遇到多个结果集,则将在 DataSet中创建多个表。 这些表的命名方式为默认名称 Table 加上N,N 从 0 开始递增,如以 Table0 为第一个表名,依次类推。 如果以参数形式向 Fill 方法传递表名,则这些表的命名方式为默认名称 TableName 加上N,N 从 0 开始递增,如以 TableName0 为第一个表名,依次类推。

从多个 DataAdapter 填充 DataSet

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

示例

以下代码示例从 Microsoft SQL Server 上的 Northwind 数据库填充客户列表,从存储在 Microsoft Access 2000 上的 Northwind 数据库填充订单列表。 已填充的表通过 DataRelation相关联,这样,客户列表将与相应客户的订单一起显示出来。 有关 DataRelation 对象的详细信息,请参阅添加 DataRelation导航 DataRelation

' Assumes that customerConnection is a valid SqlConnection object.  
' Assumes that orderConnection is a valid OleDbConnection object.  
Dim custAdapter As SqlDataAdapter = New SqlDataAdapter( _  
  "SELECT * FROM dbo.Customers", customerConnection)  
  
Dim ordAdapter As OleDbDataAdapter = New OleDbDataAdapter( _  
  "SELECT * FROM Orders", orderConnection)  
  
Dim customerOrders As DataSet = New DataSet()  
custAdapter.Fill(customerOrders, "Customers")  
ordAdapter.Fill(customerOrders, "Orders")  
  
Dim relation As DataRelation = _  
  customerOrders.Relations.Add("CustOrders", _  
  customerOrders.Tables("Customers").Columns("CustomerID"), _
  customerOrders.Tables("Orders").Columns("CustomerID"))  
  
Dim pRow, cRow As DataRow  
For Each pRow In customerOrders.Tables("Customers").Rows  
  Console.WriteLine(pRow("CustomerID").ToString())  
  
  For Each cRow In pRow.GetChildRows(relation)  
    Console.WriteLine(vbTab & cRow("OrderID").ToString())  
  Next  
Next  
// Assumes that customerConnection is a valid SqlConnection object.  
// Assumes that orderConnection is a valid OleDbConnection object.  
SqlDataAdapter custAdapter = new SqlDataAdapter(  
  "SELECT * FROM dbo.Customers", customerConnection);  
OleDbDataAdapter ordAdapter = new OleDbDataAdapter(  
  "SELECT * FROM Orders", orderConnection);  
  
DataSet customerOrders = new DataSet();  
  
custAdapter.Fill(customerOrders, "Customers");  
ordAdapter.Fill(customerOrders, "Orders");  
  
DataRelation relation = customerOrders.Relations.Add("CustOrders",  
  customerOrders.Tables["Customers"].Columns["CustomerID"],  
  customerOrders.Tables["Orders"].Columns["CustomerID"]);  
  
foreach (DataRow pRow in customerOrders.Tables["Customers"].Rows)  
{  
  Console.WriteLine(pRow["CustomerID"]);  
   foreach (DataRow cRow in pRow.GetChildRows(relation))  
    Console.WriteLine("\t" + cRow["OrderID"]);  
}  

SQL Server Decimal 类型

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

ADO.NET 2.0 引入了对 DataSetSystem.Data.SqlTypes 的增强支持。 有关详细信息,请参阅 SqlTypes and the DataSet

OLE DB 章节

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

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

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

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

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

Using connection As OleDbConnection = New OleDbConnection( _  
  "Provider=MSDataShape;Data Provider=SQLOLEDB;" & _  
  "Data Source=(local);Integrated " & _  
  "Security=SSPI;Initial Catalog=northwind")  
  
Dim adapter As OleDbDataAdapter = New OleDbDataAdapter( _  
  "SHAPE {SELECT CustomerID, CompanyName FROM Customers} " & _  
  "APPEND ({SELECT CustomerID, OrderID FROM Orders} AS Orders " & _  
  "RELATE CustomerID TO CustomerID)", connection)  
  
Dim customers As DataSet = New DataSet()  
  
adapter.Fill(customers, "Customers")  
End Using  
using (OleDbConnection connection = new OleDbConnection("Provider=MSDataShape;Data Provider=SQLOLEDB;" +  
  "Data Source=(local);Integrated Security=SSPI;Initial Catalog=northwind"))  
{  
OleDbDataAdapter adapter = new OleDbDataAdapter("SHAPE {SELECT CustomerID, CompanyName FROM Customers} " +  
  "APPEND ({SELECT CustomerID, OrderID FROM Orders} AS Orders " +  
  "RELATE CustomerID TO CustomerID)", connection);  
  
DataSet customers = new DataSet();  
adapter.Fill(customers, "Customers");  
}  

完成 Fill 操作后, DataSet 包含两个表: CustomersCustomersOrders,其中 CustomersOrders 表示章节列。 将名为 Orders 的附加列添加到 Customers 表中,将名为 CustomersOrders 的附加列添加到 CustomersOrders 表中。 将 Orders 表中的 Customers 列设置为自动递增。 DataRelation这个 CustomersOrders是通过向上述两个表添加列创建的,其中以 Customers 表作为父表。 下表显示了一些示例结果。

TableName:Customers

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

TableName:CustomersOrders

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

另请参阅