Rellenar un conjunto de datos desde un objeto DataAdapter

El objeto DataSet de ADO.NET es una representación de datos residente en memoria que proporciona un modelo de programación relacional coherente independiente del origen de datos. DataSet representa un conjunto completo de datos que incluye tablas, restricciones y relaciones entre las tablas. Dado que DataSet es independiente del origen de datos, DataSet puede incluir datos locales de la aplicación y datos de otros muchos orígenes. La interacción con los orígenes de datos existentes se controla mediante el DataAdapter.

La propiedad SelectCommand de DataAdapter es un objeto Command que recupera datos del origen de datos. Las propiedades InsertCommand, UpdateCommandy DeleteCommand de DataAdapter son objetos Command que permiten administrar las actualizaciones de los datos en el origen de datos para reflejar las modificaciones efectuadas en los datos de DataSet. Estas propiedades se describen con más detalle en Actualización de orígenes de datos con objetos DataAdapter.

El método Fill de DataAdapter se usa para rellenar un objeto DataSet con los resultados del elemento SelectCommand de DataAdapter. Fill toma como argumentos un elemento DataSet que se debe rellenar y un objeto DataTable o el nombre del objeto DataTable que se debe rellenar con las filas que devuelve SelectCommand.

Nota:

El uso de DataAdapter para recuperar la totalidad de una tabla lleva tiempo, en especial si la tabla incluye un gran número de filas. Esto se debe a que el acceso a la base de datos, la localización y el procesamiento de los datos, y la posterior transferencia de los mismos al cliente son procesos largos. La extracción de la tabla completa al cliente también bloquea todas las filas en el servidor. Para mejorar el rendimiento, puede usar la cláusula WHERE para reducir en gran medida el número de filas que se devuelven al cliente. También puede reducir la cantidad de datos que se devuelven al cliente si enumera de forma explícita las columnas necesarias en la instrucción SELECT . Otra solución consiste en recuperar las filas por lotes (por ejemplo varios cientos de filas de una vez) y recuperar solo el siguiente lote cuando el cliente haya finalizado con el lote actual.

El método Fill utiliza el objeto DataReader de forma implícita para devolver los nombres y tipos de columna que se usan para crear las tablas de DataSet, y los datos para rellenar las filas de las tablas en DataSet. Las tablas y columnas solo se crean cuando no existen; en caso contrario, Fill utiliza el esquema existente de DataSet . Los tipos de columna se crean como tipos de .NET Framework en función de las tablas en Asignaciones de tipos de datos en ADO.NET. No se crean claves principales a menos que existan en el origen de datos y DataAdapter.MissingSchemaAction se establezca en MissingSchemaAction.AddWithKey. Si el método Fill encuentra que una tabla tiene una clave principal, sobrescribe los datos de DataSet con los del origen de datos en las filas donde los valores de columna de clave principal coinciden con los de la fila que devuelve el origen de datos. Si no se detecta ninguna clave principal, los datos se agregan a las tablas de DataSet. Fill usa las asignaciones que puedan existir al rellenar DataSet (vea Asignaciones de objetos DataAdapter, DataTable y DataColumn).

Nota:

Si SelectCommand devuelve los resultados de OUTER JOIN, DataAdapter no establece un valor PrimaryKey para el objeto DataTableresultante. Debe definir PrimaryKey para asegurarse de que las filas duplicadas se resuelven correctamente. Para obtener más información, consulte Defining Primary Keys.

En el ejemplo de código siguiente se crea una instancia de SqlDataAdapter que utiliza un objeto SqlConnection a la base de datos Northwind de Microsoft SQL Server y se rellena un objeto DataTable en un DataSet con la lista de clientes. La instrucción SQL y los argumentos SqlConnection pasados al constructor SqlDataAdapter se utilizan para crear la propiedad SelectCommand del SqlDataAdapter.

Ejemplo

' 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");  

Nota

El código que se muestra en este ejemplo no abre ni cierra explícitamente el objeto Connection. El método Fill abre de forma implícita el objeto Connection que DataAdapter utiliza cuando encuentra que la conexión no está abierta todavía. Si el método Fill ha abierto la conexión, también la cierra cuando el método Fill deja de utilizarla. Este hecho simplifica el código cuando se trabaja con una operación única, como Fill o Update. Sin embargo, en el caso de que se estén realizando varias operaciones que necesiten tener abierta una conexión, se puede mejorar el rendimiento de la aplicación llamando explícitamente al método Open de Connection, realizando las operaciones en el origen de datos y, finalmente, llamando al método Close de Connection. Es conveniente mantener abiertas las conexiones con el origen de datos el menor tiempo posible para liberar recursos, de manera que estén disponibles para otras aplicaciones cliente.

Varios conjuntos de resultados

Si DataAdapter encuentra varios conjuntos de resultados, crea varias tablas en DataSet. Las tablas reciben de forma predeterminada el nombre secuencial TableN, comenzando por "Table" que representa Table0. Si se pasa un nombre de tabla como argumento al método Fill , las tablas reciben de forma predeterminada el nombre secuencial TableNameN, comenzando por "TableName" que representa TableName0.

Llenar un DataSet desde múltiples DataAdapter

Con una instancia de DataSet se puede usar cualquier número de objetos DataAdapter. Cada DataAdapter se puede usar para rellenar uno o varios objetos DataTable y resolver de nuevo las actualizaciones en el origen de datos correspondiente. Se pueden agregar objetosDataRelation y Constraint a DataSet localmente, lo que permite relacionar datos procedentes de varios orígenes distintos. Por ejemplo, un DataSet puede contener datos de una base de datos de Microsoft SQL Server, una base de datos de IBM DB2 expuesta mediante OLE DB y un origen de datos que genera secuencias XML. La comunicación con cada origen de datos se puede controlar usando uno o varios objetos DataAdapter .

Ejemplo

En el ejemplo de código siguiente se rellena una lista de clientes a partir de la base de datos Northwind almacenada en Microsoft SQL Server, y una lista de pedidos a partir de la base de datos Northwind almacenada en Microsoft Access 2000. Las tablas rellenas se relacionan entre sí mediante DataRelation, con lo que se puede mostrar una lista de clientes con los pedidos que ha realizado cada uno. Para obtener más información sobre los objetos DataRelation, vea Agregar DataRelations y Navegar por DataRelations.

' 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"]);  
}  

Tipo decimal de SQL Server

De forma predeterminada, en DataSet se almacenan datos mediante tipos de datos de .NET Framework. En la mayor parte de las aplicaciones, estos tipos proporcionan una representación adecuada de la información del origen de datos. Sin embargo, esa representación puede ocasionar problemas cuando el tipo de datos del origen de datos es decimal o numérico de SQL Server. El tipo de datos decimal de .NET Framework permite un máximo de 28 dígitos significativos, mientras que el tipo de datos decimal de SQL Server permite 38 dígitos. Si SqlDataAdapter determina durante una operación Fill que la precisión de un campo decimal de SQL Server es superior a 28 caracteres, la fila actual no se agrega a DataTable. En su lugar, se produce el evento FillError que permite determinar si se va a producir o no una pérdida de precisión y tomar las medidas adecuadas. Para obtener más información sobre el evento FillError, vea Control de eventos de objetos DataAdapter. Para obtener el valor decimal de SQL Server, también se puede utilizar un objeto SqlDataReader y llamar al método GetSqlDecimal .

ADO.NET 2.0 incorporó la compatibilidad mejorada del elemento System.Data.SqlTypes de DataSet. Para obtener más información, consulta SqlTypes and the DataSet.

Capítulos de OLE DB

Se pueden usar conjuntos jerárquicos de filas, o capítulos (tipo DBTYPE_HCHAPTERde OLE DB y tipo adChapterde ADO), para rellenar el contenido de DataSet. Cuando OleDbDataAdapter encuentra una columna que tiene un capítulo durante una operación Fill , se crea un objeto DataTable para dicha columna y la tabla se rellena con las columnas y filas del capítulo. Para asignar un nombre a la tabla creada para la columna con capítulo se usa tanto el nombre de la tabla primaria como el de la columna con capítulo. El formato del nombre es "nombreDeTablaPrimariaNombreDeColumnaConCapítulo". Si ya existe una tabla en DataSet que tenga el nombre de la columna con capítulo, la tabla actual se rellena con los datos del capítulo. Si ninguna de las columnas de la tabla existente coincide con una de las columnas del capítulo, se agrega una nueva columna a la tabla.

Antes de que las tablas de DataSet se rellenen con los datos de las columnas con capítulos, se crea una relación entre las tablas primaria y secundaria del conjunto jerárquico de filas; para ello, se agrega una columna de tipo entero a las tablas primaria y secundaria, se establece el valor de incremento automático para la columna de la tabla primaria y se crea un objeto DataRelation usando las columnas agregadas de ambas tablas. Para asignar un nombre a la relación se utilizan los nombres de la tabla primaria y de la columna con capítulo. El formato es "nombreDeTablaPrimariaNombreDeColumnaConCapítulo".

Tenga en cuenta que la columna relacionada solo existe en DataSet. Las operaciones de relleno que se realicen posteriormente desde el origen de datos pueden provocar que se agreguen nuevas filas a las tablas en lugar de que se introduzcan los cambios en las filas existentes.

Tenga en cuenta además que, si se utiliza una sobrecarga de DataAdapter.Fill que acepte un objeto DataTable, solo se rellanará esa tabla. En este caso también se agrega a la tabla una columna de tipo entero y con incremento automático, aunque no se crea ni rellena ninguna tabla secundaria, ni se crea ninguna relación.

En el ejemplo siguiente se utiliza el proveedor MSDataShape para generar un capítulo con la columna de pedidos realizados por cada uno de los clientes de una lista. A continuación, se rellena un DataSet con los datos.

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");  
}  

Una vez completada la operación Fill , DataSet contiene dos tablas: Customers y CustomersOrders, donde CustomersOrders representa la columna con capítulo. Se agrega una columna adicional denominada Orders a la tabla Customers , y una columna adicional denominada CustomersOrders a la tabla CustomersOrders . Se establece el valor de incremento automático para la columna Orders de la tabla Customers . Se crea también una relación DataRelation, CustomersOrders, utilizando las columnas que se han agregado a las tablas, siendo Customers la tabla primaria. Las siguientes tablas muestran algunos ejemplos de los resultados.

Nombre de tabla: Customers

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

Nombre de tabla: CustomersOrders

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

Consulte también