Tutorial de ASP.NET
Vista Previa de ASP.NET 2.0

Binding to Objects

La sección anterior nos mostraba cómo enlazar controles a SqlDataSource, qué soporta propiedades para la cadena de conexión que le especificamos, sentencias SQL o procedimientos almacenados utilizados para hacer peticiones o modificar la base de datos. Mientras que ésto resulta conveniente para la mayoría de sitios pequeños o hechos por hobby, almacenar directamente las sentencias SQL en las páginas de presentación de una aplicación puede volverse insostenible muy rápidamente para aplicaciones a nivel empresarial a gran escala. Estas aplicaciones suele requerir un modelo de datos más encapsulado utilizando una capa de acceso a datos de nivel dalo o un componente de negocio (business). Afortunadamente, el control de fuente de datos de ASP.NET soporta este enfoque mediante el control ObjectDataSource.

El modelo de objeto del control ObjectDataSource es similar al del control SqlDataSource. En lugar de una propiedad ConnectionString, ObjectDataSource tiene una propiedad TypeName que especifica un tipo de objeto (nombre de clase) a inicializar para realizar las operaciones condatos. De forma similir a las propiedades de comando de SqlDataSource, el control ObjectDataSource soporta propiedades como SelectMethod, UpdateMethod, InsertMethod y DeleteMethod para especificar los métodos de los tipos asociados a los que llamaremos para realizar estas operaciones de datos. Esta seción describe técnicas para construir componentes de la capa de acceso a datos y de la capa de negocio (business) y hacerlos accesibles mediante un control ObjectDataSource.

Enlazando a una Capa de Acceso a Datos

Un componente de la capa de acceso a datos encapsula el código ADO.NET para consultar y modificar la base de datos mediante comandos SQL. Normalmente abstrae los detalles de crear una conexión y unos comandos ADO.NET, y en su lugar los hace accesibles a través de métodos a los que se puede invocar con los parámetros apropiados. Un componente típico de la capa de acceso a datos se puede declarar de la siguiente forma:
public class MyDataLayer {

public DataView GetRecords();
public DataView GetRecordsByCategory(String categoryName);
public DataView GetRecordByID(int recordID);

public int UpdateRecord(int recordID, String recordData);
public int DeleteRecord(int recordID);
public int InsertRecord(int recordID, String recordData);
}
El ObjectDataSource se le puede asociar de la siguiente forma:
<asp:ObjectDataSource TypeName="MyDataLayer" SelectMethod="GetRecords" UpdateMethod="UpdateRecord" 
DeleteMethod="DeleteRecord" InsertMethod="InsertRecord" runat="server"/>
El ObjectDataSource requiere un patrón de diseño muy específico para los objetos con los que puede trabajar. Estas restricciones son, principalmente, impuestas por el entorno estático en el que se ejecutan las aplicaciones Web. Debido a que los objetos se crean y se destruyen para servir a cada petición, el enlazada de dichos objetos con la fuente de datos debe ser también estática. Por defecto, ObjectDataSource asume un constructor por defecto(sin argumentos) para el tipo especificado en la propiedad TypeName,  aunque es posible instanciar este tipo en nombre de ObjectDataSource, haciendo que el evento ObjectCreating cree una instancia de objeto personalizada y la asigne a la propiedad ObjectInstance de los argumentos del evento. El método asociado a la propiedad SelectMethod puede devolver cualquier Objeto o lista IEnumerable, grupo o array. El el anterior ejemplo de la capa de acceso a datos, el objeto DataView implementa IEnumerable. Cómo se discutirá en la siguiente sección, estos métodos deben, además, devolver un grupo u objeto fuertemente tipado.
GetProducts() -> ProductCollection
GetProductsDataSet() -> DataSet
GetProduct (int productId) -> Product
Los métodos Update, Insert y Delete han de coger campos de elementos de datos individuales como parámetros, o, opcionalmente, un objeto de una clase agregada con propiedades públicas para los campos del elemento de datos.
UpdateProduct (int id, String name, double price, bool inStock)
UpdateProduct (Product p) // p.ID, p.Name, p.Price, p.InStock
DeleteProduct (int id)
Cómo el ejemplo de SqlDataSource, los nombres de los parámetros o propiedades de los elementos de datos pasados a los métodos Update, Delete o Insert deben coincidir con los nombres de los campos de elementos de datos que devuelve el método SelectMethod para que funcionen las actualizaciones/borrados/inserciones automáticos del GridView/DetailsView.Como en SqlDataSource, los parámetros de los métodos ObjectDataSource se pueden asociar a objetos de parámetros de datos asignados a los grupos SelectParameters, FilterParameters, UpdateParameters, DeleteParameters o InsertParameters.

El siguiente ejemplo muestra un control ObjectDataSource que hace accesible los datos de un componente de la capa de acceso a datos llamado AuthorsDB. El fichero de clase de este tipo está en el directorio App_Code, que se compila dinámicamente en tiempo de ejecución.
C# Enlazando a una Capa de Acceso a Datos

Enlazando a una Capa de Lógica de Negocio (Business)

Una cosa importante a observar de la capa de acceso a datos es que, debido a que el SelectMethod devuelve el resultado de ejecutar la consulta como un DataView, sigue mostrando el esquema de base de datos subyacente a las páginas de presentación. Otra cosa a tener en cuenta es que no hay reglas de negocio en la capa de acceso a datos; simplemente se hace consultas y devuelve resultados. Para aislar la presentación del esquema de la base de datos e introducir reglas de negocio o validación, la capa de acceso a datos se envuelve en una capa de lógica de negocio.

Una capa de lógica de negocio es similar a una capa de acceso a datos en que hace deja accesibles métodos a ObjectDataSource para enlazar controles en páginas Web. Sin embargo, en lugar de devolver directamente resultados ADO.NET, normalmente devuelve objetos fuertemente tipados que representar las entidades de negocio utilizadas por la aplicación. Ésto separa la capa de presentación del esquema de el almacén de datos subyacente, haciendo más sencillo mantener separados la parte de acceso a datos del sitio, de las páginas que consumen los datos. Con una capa intermedia bien estructurada, podremos cambiar el almacén de datos a un esquema totalmente diferente sin tener que actualizar páginas individuales de la aplicación.

Un ejemplo de la capa de lógica de negocio se da a continuación.
public class MyBusinessLayer {

public RecordCollection GetRecords();
public RecordCollection GetRecordsByCategory(String categoryName);
public RecordCollection GetRecordByID(int recordID);
public String GetRecordName(int recordID);
public Object GetRecordData(int recordID);

public int UpdateRecord(Record r);
public int DeleteRecord(Record r);
public int InsertRecord(Record r);

public int UpdateRecordData(int ID, String Data);
public int UpdateRecordName(int ID, String Name);
}

public class Record {
public int ID { get; set; }
public String Name { get; set; }
public Object Data { get; set; }
}
La principal diferentcia entre la capa de lógica de negocio y la capa de acceso a datos es que la primera devuelve un RecordCollection fuertemente tipado, de objetos "Record", en lugar de un DataView. También nos premite la operaciones de Update, Insert y Delete que cogen este "Record" como parámetro. La propiedad DataObjectTypeName de ObjectDataSource nos permite configurar el ObjectDataSource para pasar este tipo a los métodos, en lugar de valores de campos individuales. En las implementaciones de métodos de la capa de lógica de negocio podemos incluir lógica personalizada para validar las reglas de negocio Por ejemplo, podemos asegurarnos que sólo los "Records" de la categoria "In Review" se pueden actualizar, o que sólo los administradores pueden insertar nuevos registros. También podemos incluir lógica de validación para asegurarnos que los tipos de datos y los valores proporcionados como argumentos son correctos antes de insertar o modificar los datos de la base de datos. Observar que la validación en la capa de negocio no substituye la validación de entrada en la capa de presentación, qué ayuda a guiar al usuario final a introducir valores correctos antes de enviar la actualización.

El siguiente ejemplo muestra una simple capa de lógica de negocio (BLL) llamada AuthorsComponent. Internamente, esta BLL llama a la capa de acceso a datos (DAL) para realizar las operaciones en la base de datos. Por simplicidad, esta BLL no incluye ninguna regla o validación de negocio, aunque en una aplicación real lo haría. Además, cabe observar que en lugar de escribir nuestra propia clase de grupo para devolver registros fuertemente tipados, este ejemplo aprovecha una nueva característica del Framework .NET 2.0, llamada "Generics", para crear un grupo de objetos Author. Mediante grupos fuertemente tipados, ObjectDataSource puede deducir el esquema de los objetos de negocio en tiempo de diseño (en Visual Studio y otras herramientas).
C# Enlazando a una Capa de Lógica de Negocio


La siguiente ilustración muestra la interación entre el GridView, ObjectDataSource y la capa de lógica de negocio. El ObjectDataSource se configura para llamar al método GetContacts del tipo ContactsList, que devuelve un grupo de objetos "Contact". El GridView enumera estos objetos Contactos y los enlaza directamente a las propiedades (ID, Name) de este tipo para crear sus columnas. Observar que el método SelectMethod puede devolver tanto un IEnumerable de objetos Contact como un sólo objeto Contact. El ObjectDataSource envolverá siempre el resultado del SelectMethod en un IEnumerable si no implementa IEnumerable por si sólo.
Upload/figure1.gif

























 
Al igual que SqlDataSource, el control ObjectDataSource soporta la clasificación cuando SelectMethod devuelve un objeto DataSet, DataView o DataTable. Internamente, el ObjectDataSource delega en la propiedad DataView.Sort para realizar la clasificación. ObjectDataSource también soporta clasificaciones personalizadas en la implementación de SelectMethod, lo cual es muy útil si el método no devuelve un DataSet, DataView o DataTable. La clasificación personalizada se configura fijando la propiedad SortParameterName al nombre de un parámetro del método que acepte el SortExpression de la fuente de datos. Cuando invocamos el SelectMethod, ObjectDataSource pasará esta expresión a nuestro método y podremos implementar nuestra propia lógica de clasificación usando esta expresión. El ejemplo anterior muestra la implementación de una clasificación personalizada en la clase "AuthorsComponent".

ObjectDataSource también soporta paginaciçon personalizada en la implementación de SelectMethod. Ésto se configura mediante las propiedades StartRowIndexParameterName, MaximumRowsParameterName y SelectCountMethod, y se trata con más detalle en la sección Advanced Paging and Sorting de este tutorial.


Enlazando a un DataSet de Visual Studio

La construcción de una capa de enlace de datos (DAL) puede resultar tedioso debido a que, a menudo, el código ADO.NET para ejecutar las sentencias SQL o los procedimientos almacenados es el mismo, o muy similar, para diferentes métodos de la DAL. A pesar que podemos escribir nuestro propia DAL mediante código ADO.NET, utilizando las técnicas descritas arriba, Visual Studio proporciona una forma práctica de generar una DAL, basada en entradas a un asistente. La DAL es, en este caso, un objeto DataSet fuertemente tipado. El DataSet contiene tipos TableAdapter que muestran los métodos para devolver objetos DataTable fuertemente tipados. Estos métodos son apropiados para enlazar directamente a un ObjectDataSource, o para ser invocados desde los componentes de la capa de lógica de negocio.

Para añadir un DataSet a nuestro proyecto VisualStudio tenemos que hacer clic con el botón derecho en el "Solution Explorer" y seleccionar "Add New Item...", para después elegir el tipo de elemento de proyecto "DataSet". Visual Studio nos preguntará si queremos añadirlo al directorio App_Code, a lo que contestaremos "Yes" para proceder. Visual Studio añade un fichero DataSet.xsd al directorio App_Code y abre el diseñador de DataSet, lanzando por defecto el asistente de TableAdapter. Siguiendo los pasos de dicho asistente, podremos especificar las sentencias SQL o los procedimientos almacenados de nuestra base de datos y después nombrar los métodos asociados a estas consultas/comandos en la página final del asistente.
Upload/figure3.gif

 



























El TableAdapter puede mostrar dos tipos de métodos: métodos "Fill" (para rellenar los DataSet existentes) y métodos "Get" (que devuelven un objeto DataTable ya relleno). El primero es más adecuado para los clientes Windows (en los que el DataSet se mantiene en memoria durante el tiempo de vida de la aplicación), mientras que los segundos lo son para ObjectDataSource. El asistente de TableAdaptes también puede generar automáticamente los métodods "Update", "Insert" y "Delete" para nuestrar sentencias SQL (requiere que se seleccione la clave primaria). Después de completar el asistente, Visual Studio añade un nuevo tipo DataTable y TableAdapter al diseñados de DataSet.

Un TableAdapter representa el esquema de un resulset y las operaciones de Selección, Actualización y Borrado realizadas sobre el dicho esquema. Podemos añadir múltiples TableAdapters en un DataSet haciendo clic con el botón derecho en el diseñador de DataSet. También podemos añadir consultas adicionales, siempre que devuelvan el mismo esquema (campos) al TableAdapter, haciendo clic con el botón derecho en el cuadro TableAdapter del diseñador. Por ejemplo, podríamos tener un sólo TableAdapter con los métodos GetAuthors() y GetAuthorsById(int id), y necesitar un nuevo TableAdapter con el método GetTitles(). La figura muestra el diseñador de DataSet con varios TableAdapters añadidos:
Upload/figure2.gif
 

























Una vez hemos finalizado el diseño del DataSet, tenemos que salvar el fichero DataSet.xsd (ésto hace que el diseñador compile los tipos y los hace accesibles desde nuestras páginas). Podremos ver que dichos tipos son accesibles desde nuestro código:
protected void Page_Load(object sender, EventArgs e)
{
DataSetTableAdapters.PhotosTableAdapter adapter = new DataSetTableAdapters.PhotosTableAdapter();
adapter.GetPhotosForAlbum(0);
}
Sin embargo, no necesitamos llamar a estos métodos directamente desde nuestro código. En lugar de eso, podemos enlazarlos al ObjectDataSource:
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
TypeName="DataSetTableAdapters.PhotosTableAdapter"
SelectMethod="GetPhotosForAlbum">
<SelectParameters>
<asp:QueryStringParameter Name="albumID" QueryStringField="id" Type="Int32"/>
</SelectParameters>
</asp:ObjectDataSource>
El siguiente ejemplo muestra un ObjectDataSource enlazado a los métodos del DataSet.TableAdapter. Usaremos este DataSet en más ejemplos de este tutorial para mostrar cómo podemos usar los controles de datos de ASP.NET para implementar una simple aplicación de Álbum de Fotos. Observar que DetailsView usa, en este ejemplo, un nuevo tipo de campo llamado --, para mostrar imágenes. También hay que observar el uso de -- en el ObjectDataSOurce para hacer que los párametros "null" se conviertan en "DbNull" antes de pasarlos a los métodos de TableAdaptes (obligatorio).
C# Binding to a Visual Studio DataSet