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
, UpdateCommand
y 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 DataTable
resultante. 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_HCHAPTER
de OLE DB y tipo adChapter
de 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 |