adicionalmente todas las excepciones que generemos desde el modelo de datos serán capturadas y gestionadas por el validador dinámico en la interfaz de usuario. esto nos permite añadirle validaciones mucho más complejas a las entidades escribiendo un poco de código.
el lugar apropiado para realizar la validación es en la clase parcial que hemos creado antes.
si abrimos el código del modelo de datos (la clase parcial xxxx.designer.vb de la que hablamos antes), veremos que todas las entidades tienen una sección (“Defini- ción de métodos de extensibilidad”) que contiene multitud de métodos parciales con nombres típicos de eventos (figura 11).
Figura 11.- Métodos de extensibilidad de las entidades
Todos ellos son métodos parciales. esto quiere decir que si no los implementamos en otra parte de la clase, el compilador los elimina ya que no se van a usar jamás. Pero si los implementamos se podrán utilizar durante la ejecución del programa.
si nos fijamos bien veremos que hay dos métodos especiales (OnValidate y OnCreate para la validación global de la clase y la creación de la misma) y que el resto de métodos se corresponden con el nombre de los campos de la entidad y hay dos por cada campo. Los que se llaman OnXXXXChanging son métodos que
se llamarán automáticamente justo antes de cambiar el valor de la propiedad, y los OnXXXXChanged se llamarán tras haber cambiado el valor.
sabiendo esto añadir código de validación especial para un campo es una tarea sencilla, pues basta con implementar el método parcial correspondiente al cambio de valor de éste. Por ejemplo, para impedir mediante código que los stocks puedan ser negativos escribiríamos esto:
<MetadataType(GetType(MetaDataDeProducto))> _ Partial Public Class Product
Private Sub OnUnitsInStockChanging(ByVal value As System.Nullable(Of Short))
If value < 0 Then
Throw New ArgumentOutOfRangeException(“Los stocks no pueden ser negativos”)
End If End Sub End Class
a partir de ahora se mostrará el mensaje indicado cuando un usuario intente introducir un valor de inventario negativo en algún producto.
estos eventos no nos permiten validar unos campos en relación con otros de la misma entidad porque puede que no estén todavía establecidos cuando se ejecuta el evento (se van estableciendo por orden). si queremos conseguir una validación de este tipo -en la que entren en juego varios campos- deberemos usar el método parcial para la validación general de la clase, OnValidate:
Private Sub OnValidate(ByVal action As System.Data.Linq.ChangeAction) If action = ChangeAction.Insert Or action = ChangeAction.Update Then If Me.Discontinued And Me.UnitsInStock > 0 Then
Throw New ArgumentOutOfRangeException(“No se puede
asignar stock distinto de cero a productos descatalogados.”)
End If
End If End Sub
con este código comprobamos si estamos en una inserción o actualización, y en ese caso nos aseguramos de que si un producto está descatalogado no pueda tener productos en el almacén.
Todas estas excepciones se convertirán en validaciones en la interfaz del usuario, por lo que disponemos de un mecanismo muy potente para crear reglas de negocio directamente en el modelo de datos. Éstas se cumplirán en todo momento independien- temente de donde se usen posteriormente las entidades, sea con Dynamic Data o no.
10.- PlANTillAS dE cAMPoS ProPiAS
como hemos visto, dentro de la carpeta “DynamicData/FieldTemplates” están defini- dos los controles para visualizar y editar los tipos de datos más comunes. No obstante en muchos casos estas plantillas de controles serán insuficientes y necesitaremos
editar los datos de alguna forma especial o bien habrá algún tipo de dato que no sea reconocido. en estos casos podemos crear nuestras propias plantillas de campos.
Lo primero que tenemos que decidir es el nombre de la plantilla, ya que será la forma que tenga Dynamic Data de reconocerla y usarla. como ya hemos visto, pueden existir dos variantes de una plantilla de campo: para visualización o para edición. ambas llevan el mismo nombre sólo que la de edición va seguida del sufijo _Edit.
supongamos que queremos crear una plantilla que nos permita editar algunos campos que pueden contener hTML. en lugar de usar el control de texto normal podemos usar un control editor de hTML.
en el código de ejemplo descargable he creado un campo personalizado llamado HTMLText que permite visualizar y editar campos hTML. Para ello tengo dos archi- vos: “hTMLtext.ascx”, que sirve para visualizar, y “hTMLText_edit.ascx” que sirve para editar el contenido. ambos están en la carpeta “FieldTemplates” del proyecto.
el control de visualización es un control Literal que mostrará cualquier hTML que le indiquemos en su propiedad Text. La única cuestión a tener en cuenta es que usaremos la propiedad FieldValue en lugar de la más habitual FieldValueString del control FieldTemplateUserControl del que hereda. el motivo es que la segunda devuelve la cadena formateada para hTML, por lo que visualizaríamos el código pero no se renderizaría en la página como hTML.
el control de edición utiliza un control Editor de los que vienen disponibles gratuitamente en las versiones del aJaX control Toolkit a partir de la 3.0.30515 (descargable desde http://ajaxcontroltoolkit.codeplex.com/). el código es muy sencillo y casi idéntico al de cualquier otra plantilla: simplemente se ajustan los validadores y se define el contenido del control (propiedad Content de éste) como valor a extraer de la edición.
Una vez creada la plantilla sólo nos resta indicar en los metadatos qué campos queremos que sean editables con ella. La forma de hacerlo es mediante el atributo
UIHint, estudiado en el epígrafe 9.1. Por ejemplo, vamos a hacer que la descripción
de las categorías de productos sean editables en formato hTML. el código necesario es el de la figura 12.
el atributo indica el nombre del control y Dynamic Data se encarga de llamar a la versión apropiada según se esté visualizando o editando el campo. si sólo tuviésemos uno de las dos variantes se usaría el control más apropiado para el tipo de datos subyacente. así, en este ejemplo si no tuviésemos el control de visualización (o sea, “hTMLText.ascx”) se usaría el correspondiente a campos de texto: “Text.ascx”, y lo mismo en caso contrario.
en la figura 13 vemos el editor de campos en funcionamiento, tanto en edición como en visualización.
Figura 13.- Nuestros controles para editar y visualizar hTMl
11.- dyNAMic dATA EN PÁgiNAS ProPiAS
Desde el principio del capítulo he comentado que es posible sacarle partido a esta tecnología sin usar necesariamente la parte de generación automática de interfaces ni las rutas. De hecho, salvo en los casos en los que hayamos protegido debidamente y de manera consciente el acceso a las rutas autogeneradas, es incluso mejor usar
en realidad a estas alturas ya sabes lo necesario para sacarle partido, pues todo lo que hemos visto es válido.
si tenemos el modelo de datos correctamente registrado (del modo que se explica en el epígrafe 4 de este capítulo), lo único que tenemos que hacer en nuestras páginas para sacar partido a Dynamic Data es arrastrar un control DynamicDataManager a la superficie de diseño de la página.
Figura 14.- los controles de datos dinámicos
como ya hemos visto en el punto 5.1, este control registra a otros controles para poder sacarle partido a la generación automática de campos de Dynamic Data. si en nuestra página tenemos un GridView y un control LinqDataSource configurados para trabajar conjuntamente, sólo tenemos que registrar la rejilla con nuestro Dyna-
micDataManager para que ésta sea capaz de generar la visualización y edición de
las columnas de datos, bien declarativamente:
<asp:DynamicDataManager ID=”DynamicDataManager1” runat=”server” AutoLoadForeignKeys=”true”>
<DataControls>
<asp:DataControlReference ControlID=”GridView1” /> </DataControls>
Bien mediante código
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System. EventArgs) Handles Me.Init
DynamicDataManager1.RegisterControl(GridView1) End Sub
ahora, en lugar de usar los campos enlazados normales de una rejilla podemos utilizar los campos dinámicos simplemente indicando el nombre del campo que van a representar:
<asp:GridView ID=”GridView1” runat=”server” AllowPaging=”True” AllowSorting=”True” AutoGenerateColumns=”False” CellPadding=”4” DataKeyNames=”CategoryID” DataSourceID=”LinqDataSource1”
GridLines=”None” PageSize=”3”> <Columns>
<asp:DynamicField DataField=”CategoryName” runat=”server” /> <asp:DynamicField DataField=”Description” runat=”server” /> </Columns>
</asp:GridView>
al usar este tipo especial de campos enlazados, soportados nativamente por los controles GridView y DetailsView, podremos sacar partido a todo lo que hemos visto sobre Dynamic Data. se usarán las plantillas de controles apropiadas para cada uno, se hará la validación automática de los campos, etc... ello nos libera de una gran cantidad de trabajo pues no tendremos que preocuparnos por editar cada una de las columnas de la rejilla para hacer validaciones, dar formatos, permitir la selección de elementos relacionados, etc...
Los controles ListView y FormView permiten también todo el trabajo con campos dinámicos, pero en este caso no soportan los campos enlazados de tipo Dynamic- Field. Para poder exprimir la potencia de los datos dinámicos en este caso, debemos incluir controles de tipo DynamicControl dentro de su marcado. Básicamente estos controles dinámicos se comportan igual que los campos dinámicos de la rejilla, pero los podemos usar en el hTML de estos otros controles que no tienen soporte nativo para datos dinámicos. Por ejemplo, un ListView podría tener la siguiente definición para sus Items:
<ItemTemplate> <tr> <td> <asp:DynamicControl runat=”server” DataField=”ProductID” /> </td> <td> <asp:DynamicControl runat=”server”
DataField=”ProductName” /> </td> <td> <asp:DynamicControl runat=”server” DataField=”Supplier” /> </td> <td> <asp:DynamicControl runat=”server” DataField=”UnitPrice” /> </td> <td> <asp:DynamicControl runat=”server” DataField=”Discontinued” /> </td> </tr> </ItemTemplate>
como vemos, tan fáciles de utilizar como los campos dinámicos enlazados de la rejilla.
Del mismo modo podría emplear un control DinamycEntity como hemos visto al analizar las plantillas.
Todo lo que hemos visto de modificar los metadatos del modelo, asignar controles específicos para edición y visualización, etc... sigue siendo válido para estos contro- les y los utilizaremos igual. La mejor forma de aprender a usarlos en la práctica es analizar bien, como ya dije anteriormente, las plantillas por defecto que trae visual studio para la interfaz autogenerada, pues en realidad lo único que hacen éstas es deducir de la ruta qué tablas van a utilizar. el resto es lo mismo que podríamos hacer nosotros en cualquier página.
12.- EN rESuMEN
Dynamic Data es una tecnología espectacular aparecida con el service pack 1 de .NeT 3.5 y disponible en ediciones superiores, que nos permite generar interfaces completas de gestión de datos de manera automática. Podemos personalizar casi sin límite el comportamiento de las interfaces generadas.
cualquier programador Web podrá ver la ganancia de productividad que obtiene con esta tecnología sin perder por ello potencia ni capacidad de adaptación a nece- sidades concretas.
147 Una de las tareas más comunes que debemos realizar como programadores es la de filtrar datos. Imagínate el típico listado en una aplicación, por ejemplo para mostrar todos los productos de la base de datos “Northwind”. como son muchos, debes facili- tar a los usuarios alguna manera de hacer filtros sobre los datos visualizados. De esta manera localizarán fácilmente aquellos en los que estén realmente interesados.
Lo habitual en estos casos es que tengas que interceptar el evento de algún botón de búsqueda, y entonces modificar dinámicamente la cláusula Where de la consul- ta. otra opción bastante utilizada es gestionar el evento de tipo Selecting del control origen de datos, en el cual podrás cambiar también la consulta dinámicamente.
si bien estas técnicas son relativamente sencillas, nos obligan a escribir código y son difíciles de mantener. cada vez que queramos modificar la forma de hacer la búsqueda o si necesitamos añadir más filtros a la misma tendremos que tocar el código y recompilar.
en asP.NeT 4.0 se incluye un nuevo control -y clases relacionadas- que nos permiten crear filtros de manera declarativa, sin necesidad de escribir código alguno. es otra gran idea para mejorar la productividad en tareas comunes.
1.- El coNTrol QuEryEXTENdEr
el nuevo control QueryExtender se utiliza para definir de forma declarativa filtros sobre orígenes de datos, pudiendo incluir tantas condiciones como sea necesario, y sin necesidad de escribir código. como resultado se obtiene un conjunto de re- sultados que cumpla las condiciones especificadas, ordenado según el criterio que hayamos decidido.
Los QueryExtender funcionan exclusivamente con controles de origen de datos para Linq2sQL (LinqDataSource) y para entity Framework (EntityDataSource), ya que el lenguaje de consulta que manejan por debajo es Linq.
otra cosa interesante a tener en cuenta al usarlos es que modifican directamente la expresión Linq manejada por el control origen de datos, por lo que en realidad de la base de datos se obtienen ya los datos filtrados. es decir, no es un control