Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Los TableAdapters dentro de un DataSet tipado se encargan automáticamente de conectarse a la base de datos, emitir comandos y rellenar una tabla de datos con los resultados. Sin embargo, hay ocasiones en las que queremos cuidar estos detalles y, en este tutorial, aprendemos a acceder a la configuración de nivel de comando y conexión de la base de datos en TableAdapter.
Introducción
A lo largo de la serie de tutoriales, hemos usado DataSets tipados para implementar la capa de acceso a datos y los objetos de negocio de nuestra arquitectura en capas. Como se describe en el primer tutorial, las DataTables del DataSet tipado actúan como repositorios de datos, mientras que los TableAdapters actúan como envoltorios para comunicarse con la base de datos y recuperar y modificar los datos subyacentes. TableAdapters encapsula la complejidad implicada en el trabajo con la base de datos y nos evita tener que escribir código para conectarse a la base de datos, emitir un comando o rellenar los resultados en una DataTable.
Sin embargo, hay ocasiones en las que es necesario ensarcar en las profundidades del TableAdapter y escribir código que funciona directamente con los objetos ADO.NET. En el tutorial Incorporación de Modificaciones de Base de Datos Dentro de una Transacción, por ejemplo, agregamos métodos a TableAdapter para comenzar, confirmar y revertir transacciones ADO.NET. Estos métodos usaron un objeto interno creado manualmente SqlTransaction
que se asignó a los objetos TableAdapter SqlCommand
.
En este tutorial examinaremos cómo acceder a la configuración de nivel de comando y conexión de base de datos en TableAdapter. En concreto, agregaremos funcionalidad a ProductsTableAdapter
para que permita el acceso a la cadena de conexión subyacente y a la configuración de límite de tiempo para el comando.
Trabajar con datos mediante ADO.NET
Microsoft .NET Framework contiene una gran cantidad de clases diseñadas específicamente para trabajar con datos. Estas clases, que se encuentran en el System.Data
espacio de nombres, se conocen como las clases ADO.NET . Algunas de las clases de ADO.NET están vinculadas a un proveedor de datos determinado. Puede pensar en un proveedor de datos como un canal de comunicación que permite que la información fluya entre las clases de ADO.NET y el almacén de datos subyacente. Hay proveedores generalizados, como OleDb y ODBC, así como proveedores especialmente diseñados para un sistema de base de datos determinado. Por ejemplo, aunque es posible conectarse a una base de datos de Microsoft SQL Server mediante el proveedor OleDb, el proveedor SqlClient es mucho más eficaz, ya que se diseñó y optimicó específicamente para SQL Server.
Cuando se accede mediante programación a los datos, se suele usar el siguiente patrón:
- Establezca una conexión a la base de datos.
- Emita un comando.
- En el caso
SELECT
de las consultas, trabaje con los registros resultantes.
Hay clases ADO.NET independientes para realizar cada uno de estos pasos. Para conectarse a una base de datos mediante el proveedor SqlClient, por ejemplo, use la SqlConnection
clase . Para emitir un INSERT
comando , UPDATE
, DELETE
o SELECT
a la base de datos, use la SqlCommand
clase .
Excepto para el tutorial Modificar bases de datos dentro de una transacción, no hemos tenido que escribir ningún código de ADO.NET de bajo nivel porque el código generado automáticamente por los TableAdapters incluye la funcionalidad necesaria para conectarse a la base de datos, emitir comandos, recuperar datos y rellenar esos datos en DataTables. Sin embargo, puede haber ocasiones en las que sea necesario personalizar esta configuración de bajo nivel. En los siguientes pasos examinaremos cómo acceder a los objetos ADO.NET utilizados internamente por los TableAdapters.
Paso 1: Examinar con la propiedad de conexión
Cada clase TableAdapter tiene una Connection
propiedad que especifica información de conexión de base de datos. El tipo de datos de esta propiedad y su valor ConnectionString
vienen determinados por las selecciones realizadas en el asistente de configuración de TableAdapter. Recuerde que cuando por primera vez agregamos un TableAdapter a un DataSet tipado, este asistente nos pide el origen de la base de datos (vea la figura 1). La lista desplegable de este primer paso incluye esas bases de datos especificadas en el archivo de configuración, así como cualquier otra base de datos en las conexiones de datos del Explorador de servidores. Si la base de datos que queremos usar no existe en la lista desplegable, se puede especificar una nueva conexión de base de datos haciendo clic en el botón Nueva conexión y proporcionando la información de conexión necesaria.
Figura 1: Primer paso del Asistente para configuración de TableAdapter (haga clic para ver la imagen de tamaño completo)
Dediquemos un momento a inspeccionar el código de la propiedad TableAdapter s Connection
. Como se indicó en el tutorial Creación de una capa de acceso a datos , podemos ver el código TableAdapter generado automáticamente; para ello, vaya a la ventana Vista de clases, explore en profundidad la clase adecuada y, a continuación, haga doble clic en el nombre del miembro.
Vaya a la ventana Vista de clases; para ello, vaya al menú Ver y elija Vista de clases (o escribiendo Ctrl+Mayús+C). En la mitad superior de la ventana Vista de clases, navegue hasta el NorthwindTableAdapters
espacio de nombres y seleccione la clase ProductsTableAdapter
. Esto mostrará los miembros de ProductsTableAdapter
en la mitad inferior de la vista de clase, como se muestra en la Figura 2. Haga doble clic en la Connection
propiedad para ver su código.
Figura 2: Double-Click la propiedad de conexión en la vista de clases para ver su código generado automáticamente
Las propiedades de TableAdapter Connection
y otro código relacionado con la conexión se muestran a continuación.
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;
}
}
}
}
Cuando se crea una instancia de la clase TableAdapter, la variable _connection
miembro es igual a null
. Cuando se accede a la Connection
propiedad, primero comprueba si se ha creado una instancia de la _connection
variable de miembro. Si no es así, se invoca el método InitConnection
, que instancia _connection
y establece su propiedad ConnectionString
en el valor de la cadena de conexión especificado en el primer paso del asistente de configuración de TableAdapter.
La Connection
propiedad también se puede asignar a un SqlConnection
objeto . Al hacerlo, asocia el nuevo SqlConnection
objeto a cada uno de los objetos TableAdapter.SqlCommand
Paso 2: Exponer la configuración de Connection-Level
La información de conexión debe permanecer encapsulada dentro de TableAdapter y no ser accesible para otras capas de la arquitectura de la aplicación. Sin embargo, puede haber escenarios en los que la información de nivel de conexión del TableAdapter deba ser accesible o personalizable para una consulta, usuario o página de ASP.NET.
Vamos a ampliar ProductsTableAdapter
en el Northwind
conjunto de datos para incluir una ConnectionString
propiedad que pueda usar la capa lógica de negocios para leer o cambiar la cadena de conexión usada por el TableAdapter.
Nota:
Una cadena de conexión es una cadena que especifica información de conexión de base de datos, como el proveedor que se va a usar, la ubicación de la base de datos, las credenciales de autenticación y otras configuraciones relacionadas con la base de datos. Para obtener una lista de los patrones de cadena de conexión usados por una variedad de almacenes de datos y proveedores, consulte ConnectionStrings.com.
Como se describe en el tutorial Creación de una capa de acceso a datos , las clases generadas automáticamente de Typed DataSet se pueden ampliar mediante el uso de clases parciales. En primer lugar, cree una subcarpeta en el proyecto denominado ConnectionAndCommandSettings
debajo de la ~/App_Code/DAL
carpeta.
Figura 3: Agregar una subcarpeta denominada ConnectionAndCommandSettings
Agregue un nuevo archivo de clase denominado ProductsTableAdapter.ConnectionAndCommandSettings.cs
y escriba el código siguiente:
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;
}
}
}
}
Esta clase parcial agrega una public
propiedad denominada ConnectionString
a la ProductsTableAdapter
clase que permite que cualquier capa lea o actualice la cadena de conexión de la conexión subyacente de TableAdapter.
Con esta clase parcial creada (y guardada), abra la ProductsBLL
clase . Vaya a uno de los métodos existentes y escriba Adapter
, luego presione la tecla de punto para mostrar IntelliSense. Debería ver la nueva ConnectionString
propiedad disponible en IntelliSense, lo que significa que puede leer o ajustar este valor desde el BLL mediante programación.
Exposición del objeto de conexión completo
Esta clase parcial expone solo una propiedad del objeto de conexión subyacente: ConnectionString
. Si desea que todo el objeto de conexión esté disponible más allá de los límites de TableAdapter, también puede cambiar el nivel de protección de la Connection
propiedad. El código generado automáticamente que hemos examinado en el paso 1 mostró que la propiedad TableAdapter s Connection
está marcada como internal
, lo que significa que solo las clases del mismo ensamblado pueden tener acceso a ella. Sin embargo, esto se puede cambiar a través de la propiedad TableAdapter s ConnectionModifier
.
Abra el Northwind
Conjunto de datos, haga clic en ProductsTableAdapter
en el Diseñador y vaya a la ventana de Propiedades. Allí verá el ConnectionModifier
configurado a su valor predeterminado, Assembly
. Para que la Connection
propiedad esté disponible fuera del ensamblado typed DataSet, cambie la ConnectionModifier
propiedad a Public
.
Figura 4: El nivel de accesibilidad de la Connection
propiedad se puede configurar mediante la propiedad ConnectionModifier
(Haga clic para ver la imagen a tamaño completo)
Guarde dataSet y vuelva a la ProductsBLL
clase . Como antes, vaya a uno de los métodos existentes y escriba Adapter
, a continuación, presione la tecla de punto para abrir IntelliSense. La lista debe incluir una Connection
propiedad, lo que significa que ahora puede leer o asignar mediante programación cualquier configuración de nivel de conexión de BLL.
Paso 3: Examinar las propiedades de Command-Related
TableAdapter consta de una consulta principal que, de forma predeterminada, tiene instrucciones generadas automáticamente INSERT
, UPDATE
y DELETE
. Esta consulta principal INSERT
, UPDATE
, y DELETE
declaraciones se implementan en el código del TableAdapter como un objeto adaptador de datos de ADO.NET a través de la propiedad Adapter
. Al igual que con su Connection
propiedad, el proveedor de datos utilizado determina el tipo de datos de la Adapter
propiedad . Dado que estos tutoriales usan el proveedor SqlClient, la Adapter
propiedad es de tipo SqlDataAdapter
.
La propiedad Adapter
del TableAdapter tiene tres propiedades de tipo SqlCommand
que usa para emitir las INSERT
instrucciones, UPDATE
y DELETE
.
InsertCommand
UpdateCommand
DeleteCommand
Un SqlCommand
objeto es responsable de enviar una consulta determinada a la base de datos y tiene propiedades como : CommandText
, que contiene la instrucción SQL ad hoc o el procedimiento almacenado que se va a ejecutar; y Parameters
, que es una colección de SqlParameter
objetos . Como vimos en el tutorial Creación de una capa de acceso a datos , estos objetos de comando se pueden personalizar a través de la ventana Propiedades.
Además de su consulta principal, TableAdapter puede incluir un número variable de métodos que, cuando se invocan, envían un comando especificado a la base de datos. El objeto de comando de la consulta principal y los objetos de comando para todos los métodos adicionales se almacenan en la propiedad CommandCollection
del TableAdapter.
Echemos un momento a ver el código generado por ProductsTableAdapter
en dataSet Northwind
para estas dos propiedades y sus variables de miembro auxiliares y métodos auxiliares:
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;
}
}
El código de las Adapter
propiedades y CommandCollection
imita estrechamente el de la Connection
propiedad . Hay variables de miembro que contienen los objetos usados por las propiedades. Los descriptores de acceso de propiedades get
comienzan comprobando si la variable miembro correspondiente es null
. Si es así, se llama a un método de inicialización que crea una instancia de la variable miembro y asigna las propiedades principales relacionadas con el comando.
Paso 4: Exponer la configuración de Command-Level
Idealmente, la información de nivel de comando debe permanecer encapsulada dentro de la capa de acceso a datos. Sin embargo, si esta información se necesita en otras capas de la arquitectura, se puede exponer a través de una clase parcial, al igual que con la configuración de nivel de conexión.
Dado que TableAdapter solo tiene una sola Connection
propiedad, el código para exponer la configuración de nivel de conexión es bastante sencillo. Las cosas son un poco más complicadas al modificar la configuración de nivel de comando porque TableAdapter puede tener varios objetos de comando: , InsertCommand
UpdateCommand
y DeleteCommand
, junto con un número variable de objetos de comando en la CommandCollection
propiedad . Al actualizar la configuración de nivel de comando, esta configuración deberá propagarse a todos los objetos de comando.
Por ejemplo, imagine que había ciertas consultas en el TableAdapter que tardaban un tiempo extraordinariamente largo en ejecutarse. Al utilizar el TableAdapter para ejecutar una de esas consultas, es posible que deseemos aumentar una propiedad del objeto de comando. Esta propiedad especifica el número de segundos que se deben esperar a que el comando se ejecute y el valor predeterminado sea 30.
Para permitir que el BLL ajuste la CommandTimeout
propiedad, agregue el siguiente public
método al uso del ProductsDataTable
archivo de clase parcial creado en el paso 2 (ProductsTableAdapter.ConnectionAndCommandSettings.cs
):
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;
}
Este método se puede invocar desde el BLL o la capa de presentación para establecer el tiempo de espera del comando para todos los comandos emitidos por esa instancia de TableAdapter.
Nota:
Las Adapter
y CommandCollection
propiedades están marcadas como private
, lo que significa que solo pueden ser accedidas por código dentro del TableAdapter. A diferencia de la Connection
propiedad , estos modificadores de acceso no son configurables. Por lo tanto, si necesita exponer propiedades a nivel de comando a otras capas de la arquitectura, debe utilizar el enfoque de clase parcial descrito anteriormente para proporcionar un método o una propiedad public
que lea o escriba en los objetos de comando private
.
Resumen
Los TableAdapters dentro de un DataSet tipado sirven para encapsular los detalles y la complejidad del acceso a datos. Con TableAdapters, no tenemos que preocuparnos de escribir ADO.NET código para conectarse a la base de datos, emitir un comando o rellenar los resultados en una DataTable. Todo se controla automáticamente para nosotros.
Sin embargo, puede haber ocasiones en las que sea necesario personalizar los ADO.NET de bajo nivel específicos, como cambiar la cadena de conexión o los valores predeterminados de tiempo de espera de la conexión o del comando. TableAdapter tiene las propiedades Connection
, Adapter
y CommandCollection
generadas automáticamente, pero estas son internal
o private
de forma predeterminada. Esta información interna se puede exponer al ampliar el TableAdapter mediante clases parciales para incluir métodos o propiedades public
. Como alternativa, el modificador de acceso de la propiedad del "TableAdapter" Connection
puede configurarse a través de la propiedad del "TableAdapter" ConnectionModifier
.
¡Feliz programación!
Acerca del autor
Scott Mitchell, autor de siete libros de ASP/ASP.NET y fundador de 4GuysFromRolla.com, ha estado trabajando con tecnologías web de Microsoft desde 1998. Scott trabaja como consultor independiente, entrenador y escritor. Su último libro es Sams Teach Yourself ASP.NET 2.0 en 24 horas. Se puede contactar con él en mitchell@4GuysFromRolla.com.
Agradecimientos especiales a
Esta serie de tutoriales contó con la revisión de muchos revisores que fueron de gran ayuda. Los principales revisores de este tutorial fueron Burnadette Leigh, Søren Jacob Lauritsen, Teresa Murphy y Hilton Geisenow. ¿Le interesa revisar mis próximos artículos en MSDN? Si es así, mándame un mensaje a mitchell@4GuysFromRolla.com.