Enlazando a Bases de
Datos
Uno de los tipos de datos más comunes que se suelen representar en
aplicaciones Web son datos provenientes de bases de datos SQL:
- Microsoft SQL Server
- Oracle
- Otro almacén de datos OLEDB o ODBC.
El control SqlDataSource
representa una conexión directa a una base de datos en una aplicación
Web, que puede ser usada por los controles de enlazado de datos para
obtener los datos de forma automática.
Debido a que las peticiones de datos se especificar directamente como
propiedades de los controles de fuente de datos, a veces se le llama "modelo de dos capas",
ya que las peticiones de datos se mantienen en el código de la página.
Por esta razón, el control SqlDataSource está dirigido hacia los sitios
pequeños hechos por hobby o personales, que no requieren una
encapsulación total de los objetos de datos de nivel medio.
En posteriores secciones del tutorial se hablará del control ObjectDataSource,
destinado a empresas mayores, que necesitan encapsulación de nivel
medio de las peticiones a base de datos.
El Control GridView
Es un nuevo control de enlazado de datos de ASP.NET 2.0 para presentar
los datos en un formato
de rejilla tabular. Cada fila de la rejilla corresponde a
un registro de datos y las columnas representan los campos del registro.
El control GridView soporta las siguientes características:
•
Vincular controles de fuente a datos.
• Capacidades de clasificación.
• Capacidades de actualización y borrado.
• Capacidades de paginación.
• Capacidades de selección de columnas.
• Acceso mediante código al modelo de
objeto GridView para poder establecer las propiedades y manejar los
eventos.
• Nuevos tipos de columnas como
CheckBoxField y ImageField.
• Múltiples campos de datos para las
columnas de hiperenlaces.
• Múltiples campos de datos llaves para
selección, actualiación y borrado.
• Apariencia personalizable a través de
temas y estilos.
Creando un Informe de Datos
El tipo más simple que podemos encontrar en una página orientada a
objetos es un informe de
sólo-lectura, que muestra los datos pero no permiten que
el usuario manipule la presentación o modifique los datos.
Para crear un informe de sólo-lectura de una base de datos SQL:
- Configurar un SqlDataSource en la página
- Conectar un control enlazado a datos, como por ejemplo el
GridView, a la fuente de datos, especificando la propiedad DataSourceID
property.
El siguiente ejemplo nos muestra un control GridView asociado
a un SqlDataSource.
<form
runat="server">
<asp:GridView
ID="GridView1"
DataSourceID="SqlDataSource1" runat="server"/>
<asp:SqlDataSource
ID="SqlDataSource1" runat="server"
SelectCommand="SELECT * FROM [authors]"
ConnectionString="<%$ ConnectionStrings:Pubs %>" />
</form>
La propiedad ConnectionString
del SqlDataSource
especifica la cadena de conexión a la base de datos y la propiedad SelectCommand
especifica la consulta a ejecutar para obtener los datos.
La cadena de conexión se puede especificar literalmente en la página,
pero en este caso hemos asignado dicha propiedad mediante una nueva
expresión que obtiene
el valor del fichero Web.config.
En el siguiente ejemplo, un control GridView se enlaza a un control
SqlDataSource conectado a una base de datos Access y otra SQL
Server que se definen previamente en el fichero Web.config
El control SqlDataSource
no se limita a conexiones con bases de datos de SQL Server,
sino que en realidad puede conectarse a cualquier proveedor ADO.NET
configurado como System.Data.Common.DbProviderFactory. Por defecto, hay
cuatro proveedores incluidos en el fichero machine.config del Framework
.NET:
•
ODBC
• OLEdb
• Oracle
• SQLClient
La propiedad ProviderName
de SqlDataSource
se puede establecer a un nombre invariante de cualquier proveedor (por
defecto System.Data.SqlClient).
En el ejemplo anterior, el control GridView
se "reflejaba contra" los campos de los registros de datos devueltos
por SqlDataSource
para generar dinámicamente las columnas de la rejilla. También podemos
especificar las columnas explícitas que queremos mostrar añadiendo
objetos DataControlField
a la colecciónde Columnas del GridView.
Esto nos permite especificar exactamente que columnas hay que mostrar y
su orden relativo.
El siguiente ejemplo muestra una colección de objetos BoundField y
CheckBoxField en la colección de Columnas del GridView.
Otro tipo de campos que pueden ser asignados a esta colección son ImageField,
HyperLinkField, CommandField, ButtonField y TemplateField.
La propiedad SelectCommand
de SqlDataSource
también se puede configurar con un nombre de procedimiento almacenado
en lugar de un comando SQL. Para permitir esto, hay que establecer la propiedad
SelectCommandType a "StoredProcedure".
Por defecto el control SqlDataSource
devuelve un objeto DataView
desde un objeto DataSet
que contiene los resultados de la consulta. Podemos configurar el
control SqlDataSource para devolver los datos como un objeto DataReader
en su lugar, estableciendo la propiedad SqlDataSourceMode a
"DataReader". Utilizar un DataReader es, generalmente, mejor en cuanto
a rendimiento que utilizar un DataSet cuando sólo necesitamos acceso
read-only o "fordward-only" a los datos. Sin embargo, es importante
observar que la capacidad de clasificación del control SqlDataSource se
deshabilitará en este modo.
Configuración de Cadenas de Conexión
En los ejemplos anteriores, SqlDataSource hace referencia a la cadena
de conexión a la base de datos por su nombre, utilizando la nueva
sintaxis declarativa de ASP.NET 2.0 que resuelve el valor de la cadena
de conexión en tiempo de ejecución. La cadena de conexión se almacena
en el fichero Web.config en la sección de configuración
<connectionStrings>, de forma que es sencillo de
mantenerlo en un solo lugar para todas las páginas de la aplicación.
<configuration>
<connectionStrings>
<add name="Pubs"
connectionString="Server=(local);
Integrated Security=True;
Database=pubs;"
providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>
Clasificación y Paginación de Datos
Una de las principales ventajas del control GridView sobre otros
controles de enlazado de datos es su habilidad para aprovechar las
propiedades de la fuente de datos. En lugar de dejar en manos del
código de la página la clasificación o paginación de los datos, el
control GridView puede realizar estas operaciones de forma automática,
siempre que la fuente de datos esté configurada para ello.
El control SqlDataSource soporta la clasificación cuando la propiedad
DataSourceMode se configura como "DataSet". Para permitir clasificación
en la UI usando un control GridView hay que configurar la propiedad
AllowSorting a "verdadero". Ésto provoca que el control GridView cree
botones de enlazado para las cabeceras de sus columnas, en los que
podamos hacer clic para clasificar la columna. El control GridView pasa
la expresión SortExpression asociada con el campo de la columna al
control de la fuente de datos, que devuelve los datos clasificados al
GridView.
La sintaxis de SortExpression que espera SqlDataSource es la misma
que la de la propiedad Sort de System.Data.DataView, aunque
otras fuentes de datos pueden soportar sintaxis diferentes. Debido a
que el comportamiento de clasificación de SqlDataSource depende la
propiedad DataViewSort, SqlDataSource sólo soporta la clasificación en
modo DataSet; si se configura como DataReader, la clasificación se
deshabilita. Normalmente asignaremos el SortExpression a un sólo nombre
de campo asociado con una columna del GridView. El GridView alternará
de forma automática entre "ASC" o "DESC" en SortExpression en cada
clic, para conmutar entre orden de clasificación ascendente o
descendente.
También podemos permitir la paginación de la UI en el control GridView,
poniendo la propiedad AllowPaging a verdadero. El GridView puede
paginar cualquier valor devuelto por una fuente de datos que soporte la
interfaz ICollection. El DataView que devuelve SqlDataSource cuando
está en en modo DataSet soporta dicha interfaz, de forma que GridView
puede (paginar)"page over" el resultado. Cuando se encuentra en mode
DataReader, el GridView no puede "page over" los datos devueltos por
SqlDataSource. El siguiente ejemplo nos muestra la UI de paginación del
GridView con un SqlDataSource en modo DataSet..
También podemos personalizar el estilo y la configuración del
paginador, configurando las propiedades PagerStyle y PagerSettings,
respectivamente. PagerStyle determina el aspecto y la sensación del
paginador, mientras que PagerSettings determina el tipo de paginación a
usar (numérica o con botones Siguiente/anterior), la posición del
paginador y opciones relacionadas. El siguiente ejemplo muestra algunos
de estos estilos y ajustes aplicados al paginador de GridView.
Observar que la operación de paginación del anterior ejemplo la está
realizando íntegramente el control GridView sobre el DataView devuelto
por SqlDataSource, que soporta la interfaz Collection. En este caso,
el GridView obtiene todos los datos de la fuente de datos, presenta un
subconjunto de las filas y después descarta las restantes. A esto se le
llama a veces "paginación UI", porque la lógica de paginación se da en
la capa de presentación del control GridView.
Aunque sea conveniente
para paginar colecciones arbitrarias, ésta no es la forma más eficiente
de paginar los datos. también es posible configurar la paginación en el
nivel de la interfaz de la fuente de datos, de forma que el GridView
solo pide a la fuente de datos las filas que necesita para representar
la página. El control SqlDataSource no soporta, por ahora, paginación a
nivel de interfaz.
Actualizando y Borrando Datos
Además de clasificación y paginación, el control GridView también
permite preparar la UI para la modificación de los datos mediante
operaciones de Actualización y Borrado, siempre que la fuente de datos
asociada se configure para soportar dichas funcionalidades.
El control
SqlDataSource soporta las operaciones de Actualización cuándo se
establece la propiedad UpdateCommand y las de Borrado cuando la
propiedad DeleteCommand se establece a un comando válido de
actualización o borrado o a un procedimiento almacenado.
UpdateCommand
o DeleteCommand deben contener parámetros de substitución para cada
valor que pasará el control GridView (más sobre esto abajo).
También
podemos especificar una colección de UpdateParameters o
DeleteParameters para establecer las propiedades de cada parámetro,
tales como el tipo de parámetro, la dirección de entrada/salida o el
valor por defecto.
<asp:SqlDataSource
ID="SqlDataSource1" runat="server"
ConnectionString="<%$
ConnectionStrings:Pubs %>"
SelectCommand="SELECT
[au_id], [au_lname], [au_fname], [state] FROM [authors]"
UpdateCommand="UPDATE
[authors] SET [au_lname] = @au_lname, [au_fname] = @au_fname, [state] =
@state WHERE [au_id] = @au_id"
DeleteCommand="DELETE
FROM [authors] WHERE [au_id] = @au_id"/>
Para permitir la Actualización y el Borrado desde la UI en el GridView,
podemos establecer las propiedades AutoGenerateEditButton y
AutoGenerateDeleteButton a verdadero, o añadir un CommandField al
control GridView y habilitar sus propiedades ShowEditButton y
ShowDeleteButton. El GridView soporta la edición o borrado de una fila
cada vez. Para editar, el usuario pondrña la fila en modo de edición
haciendo clic sobre el botón "Edit" y después confirmará la
Actualización haciendo clic sobre el botón "Update" mientras la fila
esté en modo de edición. El usuario también puede hacer clic sobre el
botón "Cancel" para cancelar la operación de edición y volver al modo
de sólo-lectura. El siguiente ejemplo muestra el GridView y la
SqlDataSource configurados para la actualización de filas de datos.
Una propiedad importante que juega un papel especial en las operaciones
de Actualización y Borrado es la propiedad de DataKeyNames. Esta
propiedad se fija al valor de los nombres de los campos de la fuente de
datos que forman parte de la llave primaria mediante la que podremos
localizar una fila concreta en la fuente de datos. Cuando especificamos
esta propiedad de forma declarativa, tendremos que separar por comas
los diferentes campos, aunque normalmente se suele tener un sólo campo
llave. Los valores de los campos especificados en la propiedad
DataKeyNames son de ida y vuelta, para poder mantener los valores
originales que tendremos que pasar a las operaciones de Actualización y
Borrado, incluso si el campo no se va a presentar como una columna en
el control GridView. Cuándo GridView invoca las operaciones de
Actualización o Borrado de la fuente de datos, pasa los valores de
estos campos en un diccionario de Llaves especiales, diferente al
diccionario de Valores que contiene los nuevos valores que ha
introducido el usuario mientras la fila estaba en modo de edición (para
operaciones de actualización). Los contenidos del diccionario de
Valores se obtienen de los controles de entrada presentados en la fila
en el modo de edición. Para excluir un valor de este diccionario,
tendremos que establecer la propiedad ReadOnly a verdadero en el
correspondiente BoundField dentro del grupo de columnas. Si estamos
usando el diseñador de GridView de Visual Studio, la propiedad ReadOnly
se pone a verdadero por defecto, para los campos de las llaves
primarias.
Observar la convención en la nomenclatura de los parámetros en la
sentencia de Actualización asignada a UpdateCommand. La capacidad
automática de invocación la operación de Actualización que tiene el
GridView y otros controles de enlazado de datos depende de la
convención de la nomenclatura para su funcionamiento. Los parámetros
deben ser nombrados como los valores de los campos asociados devueltos
por el SelectCommand. Mediante este acuerdo en la nomenclatura se hace
posible alinear los valores pasados por el control de enlazado de datos
a la fuente de datos con los parámetros de la sentencia de
actualización SQL.
La utilización de esta convención en la nomenclatura asume que el
contenido de los diccionarios de Llaves y los de Valores son mutuamente
excluyentes (es decir, los valores de los campos que deben ser
actualizados por el usuario, mientras que el control de enlazado de
datos está en modo de edición, deben nombrarse de forma diferente a los
valores de los campos utilizados para encontrar la fila a acualizar (en
la cláusula WHERE de SqlDataSource)). Otra forma de ver ésto es que
cualquier campo que se encuentre en DataKeyNames deberá ser de
sólo-lectura o invisible en el control de enlace de datos (por ejemplo,
en el conjunto de Columnas de GridView).
A pesar que es común que los campos llave sean de sólo-lectura, hay
casos en los que querremos que se puedan actualizar campos que también
se usan para encontrar la fila de datos a actualizar. Por ejemplo, si
establecemos la propiedad ReadOnly=false en un campo del conjunto de
Columnas de GridView que también forma parte de DataKeyNames, GridView
pasará el antiguo valor al campo correspondiente del diccionario de
Llaves, mientras que pasará el nuevo valor al campo del diccionario de
Valores. Para diferenciar entre estos dos valores, necesitaremos
nombrar los parámetros de forma diferente en la sentencia SQL, por
ejemplo:
<asp:SqlDataSource
ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:Pubs %>"
SelectCommand="SELECT [au_id], [au_lname], [au_fname], [state] FROM
[authors]"
UpdateCommand="UPDATE [authors] SET [au_id] = @au_id, [au_lname] =
@au_lname, [au_fname] = @au_fname, [state] = @state WHERE [au_id] =
@original_au_id"
DeleteCommand="DELETE FROM [authors] WHERE [au_id] =
@original_au_id"/>
OldValuesParameterFormatString="original_{0}"
En este ejemplo, el parámetro de nombre @original_au_id se usa para
hacer referencia al valor original del campo llave y @au_id para el
nuevo valor. La propiedad OldValuesParameterFormatString de
SqlDataSource también se establece a un formato de string válido para
el Framework .NET para indicar cómo deben ser renombrados los
parámetros en el diccionario de Llaves. Este formato también se aplica
a los viejos valores de los campos que no son llave que pasa el control
de enlace de datos cuando la propiedad ConflictDetection de
SqlDataSource se establece a CompareAllValues. En las operaciones de
Borrado, SqlDataSource aplica el diccionario de Llaves por defecto (no
hay nuevos valores para la operación de borrado), usando el valor de la
propiedad OldValuesParameterFormatString para dar formato a los nombres
de los parámetros llave.
Filtrado de Datos
Un escenario común en las páginas orientadas a datos es la habilidad de
filtrar los datos en un informe. Por ejemplo, supongamos que un usuario
pueda seleccionar entre unos valores de una DropDownList para filtrar
la cuadrícula del informe de manera que sólo se muestren las filas que
coincidan con el valor del campo. En ASP.NET 1.x necesitábamos escribir
todo este código:
• Cancelar el enlace de datos en el
Page_Load si la consulta es un postback
• Manejar el evento SelectedIndexChanged
• Añadir el SelectedValue de la
DropDownList a la colección de Parámetros de los comandos
• Ejecutar el comando y llamar a DataBind
En ASP.NET 2.0 se elimina este código mediante el uso de objetos Data
Parameter declarativos. Un "data parameter" permite que los valores
externos se asocien a operaciones de la fuente de datos de forma
declarada. Estos parámetros normalmente se asocian a una variable en un
comando o propiedad, por ejemplo, un parámetro de una sentecia SQL o un
procedimiento almacenado para SqlDataSource. Los controles de la fuente
de datos permiten acceder a las grupo de propiedades de parámetros que
contienen los objetos paramétricos para cada operación de datos
soportada. Por ejemplo:
<asp:DropDownList ID="DropDownList1" ... runat="server"/>
...
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:Pubs %>"
SelectCommand="SELECT [au_id], [au_lname], [au_fname], [state] FROM
[authors] WHERE [state] = @state">
<SelectParameters>
<asp:ControlParameter Name="state" ControlID="DropDownList1"
PropertyName="SelectedValue" />
</SelectParameters>
</asp:SqlDataSource>
Podemos configurar los parámetros de datos para devolver valores de
cualquiera de las siguientes fuentes:
- Parameter
- La clase Parameter es la base común de la que derivan el
resto de tipos de Parámetros.
- La clase Parameter también siver como implementación de
parámetros estáticos, dónde el valor se especifica de forma estática
mediante la propiedad DefaultValue.Parameters comparte la propiedad
Name común, que es el nombre del parámetro para el funcionamiento de la
fuente de datos (por ejemplo, esto encontrará el nombre del parámetro
en el SelectCommand para SqlDataSource). Todos los parámetros
comparten, también, la propiedad Type, que especifica cuál es el tipo
del valor del parámetro.
- Los parámetros también comparten la propiedad Direction,
que se usa para especificar dónde usamos el parámetro como entrada,
salida (o ReturnValue) o ambos, entrada y salida. Las fuentes de datos
suelen mostrar los parámetros de salida y devolver valores de un evento
"args" que se pasa al evento de estado de operación de la fuente de
datos. Para un ejemplo de lo aquí descrito ir a "Trabajando con
Parámetros".
- QueryStringParameter
- La clase QueryStringParameter enlaza el valor de un campo
querystring al valor del objeto Parameter. La propiedad
QueryStringField encuentra el nombre del campo querystring desde el que
se recupera el valor. La propiedad DefaultValue se devolverá siempre
que el valor querystring no esté disponible.
- ControlParameter
- La clase ControlParameter enlaza el valor de una propiedad Control al
valor de un objeto Parameter. La propiedad ControlID encuentra la ID
del Control cuya propiedad está enlazada al parámetro.
- La PropertyName
específica la propiedad del control desde la que se obtiene el valor.
El control del cuál especificamos la ID mediante ControlID puede
definir, opcionalmente, un ControlValuePropertyAttribute, que determina
el nombre de propiedad por defecto del que obtendremos el valor del
control. Esta propiedad se utilizará cuando no se establezca
explícitamente el PropertyName. El ControlValuePropertyAttribute se
aplica a las siguientes propiedades de control:
- Label.Text
- TextBox.Text
- ListControl.SelectedValue (por ejemplo,
DropDownList)
- CheckBox.Checked
- Calendar.SelectedDate
- DetailsView.SelectedValue
- GridView.SelectedValue
- TreeView.SelectedValue
- FileUpload.FileBytes
- SessionParameter
- La clase SessionParameter enlaza el valor de un objeto de Session con
el valor de un objeto Parameter. La propiedad SessionField encuentra el
nombre de la clave se Session desde la que se obtiene el valor. La
propiedad DefaultValue se devolvera si no se puede acceder al valor de
Session.
- FormParameter
- La clase FormParameter vinvula el valor de un campo de un formulario
HTML al valor de un objeto Parameter. La propiedad FormField encuentra
el nombre del campo del formulario desde el que se obtendrá el valor.
La propiedad DefaultValue se devolverá cuando el valor de Form no esté
disponible.
- CookieParameter
- La clase CookieParameter enlaza el valor de un HttpCookie al valor de
un objeto Parameter. La propiedad CookieName encuentra el nombre de la
cookie desde la que se obtendrá el valor (sólo se admiten cookies de
valor simple "simple-valued"). La propiedad DefaultValue se devolverá
cuando la cookie no esté disponible.
- ProfileParameter
- La clase ProfileParameter enlaza el valor de un objeto "User Profile"
al de un objeto Parameter. La propiedad ParameterName encuentra el
nombre del perfil desde el que se obtendrá el valor. La propiedad
DefaultValue se devolverá cuando la cookie no esté disponible. Para más
información, acudir a la sección "Perfiles de Usuario" del tutorial.
Observar la diferencia entre los parámetros de datos que se evaluan en
una fuente interna (Control QueryString, etc.) y los que se pasan para
las operaciones Actualizar, Insertar y Borrar de los ejemplos
anteriores. En el último escenario, los valores de los parámetros son
proporcionados dinámicamente por el control de enlace de datos, en este
caso GridView, qué invoca la operación de Actualización. Para las
operaciones de Actualización, Inserción y Borrado normalmente no
necesitaremos parámetros de datos asciados a valores externos. Sin
embargo, podemos incluir un objeto <asp:Parameter> (clase
base para todos los parámetros de datos) en los grupos
UpdateParameters, InsertParameters o DeleteParameters de la fuente de
datos, para especificar propiedades como Type, Direction o DefaultValue
(valor a usar si el que pasa GridView es null), para ser aplicadas a
los valores de los parámetros pasados desde el control GridView.Cacheando Datos
Otra característica de la fuente de datos es la capacidad de chachear
los datos de forma automática. A pesar que seguimos podiendo utilizar
las API's de caché para chachear los datos mediante programación,
estableciendo unas pocas características de forma declarativa en la
fuente de datos podemos obtener el mismo resultado.
Para permitir el
cacheo para el control SqlDataSource (y ObjectDataSource, que se
explica más adelante), tendremos que fijar la propiedad EnableCaching a
verdadero.Podemos especificar el tiempo (en segundos) durante el que
almacenaremos una entrada en caché, mediante la propiedad
CacheDuration. También podemos establecer la
propiedad CacheExpirationPolicy tanto a either Sliding como a Absolute,
como podemos hacer desde la API de caché. El cachero sólo es soportado
por el control SqlDataSource cuándo la propiedad DataSourceMode se fija
a "DataSet".
Por ejemplo, si fijamos CacheDuration a 5 y SlidingExpiration a
Absolute, el SqlDataSource recuperará los datos de la base de datos en
la primera petición a la página, y los almacenará en la caché. Para las
peticiones siguientes, la SqlDataSource intentará obtener la entrada de
la caché para responder la petición sin tener que mirar en la base de
datos. Después de 5 segundos (o quizá antes, si la presión de la
memoria caché es alta), la entrada de la caché se eliminará y para la
siguiente petición el SqlDataSource tendrá que volver a la base de
datos de nuevo (repitiendo el proceso de cacheo para los nuevos datos).
Si en lugar de eso fijamos CacheDuration a 5 y SlidingExpiration a
Sliding, se refrescará el time-to-live de los datos cacheados
periódicamente mientras la fuente de datos los pida al menos una vez
cada 5 segundos. Si una página pide los datos cacheados por lo menos
una vez cada 5 segundos, y no hay presión en la memoria cache, los
datos cacheados se mantendrán en la cache para siempre. Por otra parte,
si no se hacen peticiones de los datos cacheados en un periodo de 5
segundos, se eliminarán los datos de la caché y la próxima vez que se
produzca una petición el control SqlDataSource volverá a pedir los
datos a la base de datos original.
Un observador minucioso puede haberse dado cuenta que el TimeStamp
también se actualiza cada vez que se selecciona un nuevo valor para el
filtro de la DropDownlist. Ésto se debe a que cada conjunto de
parámetros único que se le pasa al SelectCommand tiene como resultado
una petición diferente a la base de datos y, poe consiguiente, una
entrada diferente en la caché (observar que si seleccionamos el mismo
valor en la DropDownList en un período de tiempo de 5 segundos el
TimeStamp no varía).
Un enfoque alternativo, que funciona bien con peticiones de datos más
pequeños, consiste en seleccionar todos los datos de la base de datos y
pasarlos a la caché, para luego filtrar esa única entrada de
la caché para los diferentes valores de los parámetros. Para soportar
ésto, el control SqlDataSource soporta la propiedad FilterExpression y
el grupo correspondiente de FilterParameters. En lugar de aplicar los
valores de los parámetros directamente sobre el comando (cómo hacíamos
en los SelectParameters), la expresión de filtrado se aplica sobre la
propiedad RowFilter del objeto DataView devuelto por la ejecución del
comando. La sintaxis de la expresión debe encajar con la esperada para
la propiedad RowFilter del DataView. Row Filter
Podemos usar parámetros de substitución para los valores de los
parámetros dentro de la FilterExpression siguiendo el estándard del
Framework .NET para la sintaxis de formato de strings, por ejemplo
"{0}", "{1}" y sucesivamente. en tiempo de ejecución, el control
SqlDataSource aplica los valores de los parámetros especificados en el
grupo FilterParameters a FilterExpression, dado formato al string con
los valores. Observar que los valores de los parámetros no son
"escaped", de manera que será necesario que los pongamos entre comillas
simples.
<asp:DropDownList ID="DropDownList1" ... runat="server"/>
...
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:Pubs %>"
SelectCommand="SELECT [au_id], [au_lname], [au_fname], [state] FROM
[authors]">
FilterExpression="state = '{0}'"
<FilterParameters>
<asp:ControlParameter Name="state" ControlID="DropDownList1"
PropertyName="SelectedValue" />
</FilterParameters>
</asp:SqlDataSource>
El cacheo de datos debe mantener un compromiso entre rendimiento (no
tenemos que volver a la base de datos en cada petición) y los datos
obsoletos (porque la entrada de caché contiene una instantánia de los
datos capturados en un momento dado). Normalmente usamos valores
relativamente pequeños en CacheDuration, para asegurarnos que los datos
de la caché están actualizados. Una situación ideal consistiría en
invalidar la entrada de la caché únicamente cuándo los datos
subyacentes cambiaran. Mientras los datos no hayan cambiado, no hay
ninguna razón para eliminar la entrada de la caché.
Una nueva característica de ASP.NET 2.0 llamada SQL Cache Invalidation,
nos permite configurar la fuente de datos para cachear los datos de
forma indefinida (o por una duración especificada) hasta que los datos
de la base de datos cambien, momento en el que la entrada de la caché
se elimina. Esta técnica nos permite utilizar valores mucho mayores
para CacheDuration y continuar garantizando que los datos que mostramos
coinciden con los valores de la base de datos. SQL Cache Invalidation
sólo es soportado por las bases de datos Microsoft™ SQL Server. Hay dos
implementaciones de esta función: una basada en notificaciones,
soportada por SQL Server 2005, y otra basada en votaciones (polling),
soportada por versiones anteriores de SQL Server. La sección de SQL
Cache Invalidation nos describe los pasos necesarios para configurar
ambas implementaciones.
Una vez hemos configurado la SQL Cache Invalidation, podemos utilizarla
desde el control de la fuente de datos, especificando la propiedad
SqlCacheDependency de la fuente de datos. Si usamos la implementación
basada en votaciones, este valor acepta un formato del tipo
connectionName:tableName. Si usamos la implementación basada en
notificaciones, fijaremos la propiedad a "CommandNotification".
Master-Details y el Control DetailsView
En la sección de Filtrado de Datos vimos cómo los controles de la
fuente de datos pueden aceptar parámetros de fuentes externas, tales
como controles de un formulario, valores de querystring, y otros. Una
técnica similar se puede emplear para crear un escenario de
"master-details". Master-details se suele referir a un "convenio
(Arreglo)" entre controles, en el que un registro seleccionado en un
control (el control "master") muestra detalles adicionales para el
registro seleccionado en otro control (el control "details"). Los
detalles adicionales pueden ser propiedades del mismo elemento de
datos, o registros relacionados que están asociados al elemento de
datos "master" a través de una relación clave externa en la base de
datos.
El control GridView soporta la propiedad SelectedValue, qué indica la
fila que está seleccionada en el GridView. La propiedad SelectedValue
evalúa el valor del primer campo especificado en la propiedad
DataKeyNames. Podemos permitir la UI para la selección el el GridView
fijando AutoGenerateSelectButton a verdadero, o añadiendo al grupo de
columnas del GridView un CommandField con ShowSelectButton fijado a
verdadero. Una vez hecho esto, la propiedad SelectedValue del GridView
puede ser asociada a un ControlParameter en una fuente de datos para
pedir los registros de detalles, de la misma forma que configurábamos
el DropDownList en los ejemplos anteriores.
Para mostrar más detalles de la fila que está seleccionada, podemos
usar otro control GridView, pero ASP.NET también incluye un nuevo
control DetailsView que sólo vale para eso. El control DetailsView
presenta un solo registro cada vez, en lugar de un grupo de registros.
De la misma forma que el GridView, DetailsView lo presenta en un
formato tabulado, a excepción de las filas correspondientes a cada
campo de datos (como las columnas GridView). Los campos se especifican
en el grupo Fields de DetailsView. Opcionalmente, el control
DetailsView también puede paginar un grupo de registros, cómo lo hace
GridView (en DetailsView, el PageSize siempre es 1).
DetailsView soporta la edición, al igual que lo hacía GridView, y
podemos permitir la UI de la misma forma, utilizando las propiedades
AutoGenerateEditButton o CommandField.ShowEditButton. Por supuesto, la
fuente de datos asociada al DetailsView tiene que ser configurada para
soportar la operación de actualización (en este caso, especificando un
UpdateCommand en SqlDataSource).
Normalmente los controles de enlazado de datos re-enlazan de forma
automática la fuente de datos cuando cambia la fuente de datos (por
ejemplo, después de una actualización). Sin embargo, en el ejemplo
anterior, el DetailsView se enlaza a una fuente de datos diferente a la
del GridView, de forma que cuando se invoca la operación de
actualización, solo el DetailsView recive el evento de cambio de su
fuente de datos. Para forzar que el GridView también re-enlace cuándo
el DetailsView realiza una actualización, podemos llamar explícitamente
al DataBind() del GridView en el evento ItemUpdated del DetailsView.
Este ejemplo también maneja eventos para no permitir la edición cuándo
una operación de clasificación o paginación del gridView ocurre al
mismo tiempo que se selecciona un valor de filtrado en el control
DropDownList.
También es común el dividir la visualización del master-details a
través de varias páginas de una aplicación Web. Para hacer ésto podemos
añadir un hipervínculo a cada fila del GridView para navegar a
diferentes páginas de detalles, pasando argumentos mediante el
querystring. En la página de detalles, la fuente de datos enlazada al
DetailsView aceptará estos argumentos mediante un objeto
QueryStringParameter.
Un hipervínculo deberá ser añadido al GridView añadiendo un objeto
HyperLinkField al grupo de Columnas de GridView. La propiedad Text del
HyperLinkField fija el texto a mostrar en el hipervínculo (por ejemplo
"View Details..."), mientras que la propiedad NavigateUrl especifica la
URL dónde navegaremos al hacer clic sobre el enlace. En lugar de
especificar una URL estática para todas las filas, es más común
especificar NavigateUrlFields para ser usado en la construcción de una
URL dinámica. Se puede fijar NavigateUrlFields de forma declarativa a
un conjunto de campos separados por comas, de la fuente de datos. La
propiedad NavigateUrlFormatString especifica el formato del estándard
del Framework .NET para la URL, mediante parámetros de substicutción
cómo {0} y {1} para substituis los valores del campo, en tiempo de
ejecución.
Insertando Datos
Al igual que el control GridView,
el control DetailsView
soporta la Actualización
y el Borrado de datos en su fuente de datos. Sin embargo, DetailsView
también soporta la
inserción de datos, cosa que no hacía GridView.
Para permitir que la SqlDataSource soporte
Inserciones, tenemos que fijar la propiedad InsertCommand a un comando
válido de inserción, con parámetros de substitución para
el valor de cada campo que es representado por el DetailsView en el
modo de Inserción. También podemos, de forma opcional, especificar un
grupo de InsertParameters que contengan los objetos de parámetros de
datos para esta operación.
Para permitir la inserción en la UI, hay que fijar la propiedad
AutoGenerateInsertButton a verdadero o añadir al grupo de campos de
DetailsView un CommandField con ShowInsertButton establecido a
verdadero.
Para pasar el DetailsView a modo de inserción, tenemos que hacer clic
en el botón clic. DetailsView representará controles de entrada para
cada campo cuándo estemos en el modo de inserción. Observar que los
campos marcados como "ReadOnly" se representan como controles de
entrada en el modo de Inserción (a pesar que no lo harían en modo
Actualización).
Para excluir un campo en el modo de Inserción, tendremos que establecer
la propiedad InsertVisible del campo a falso. Para realizar la
operación de Inserción, hay que hacer clic en el botón "Insert"
mientras estamos en el modo de inserción. Para abortar la inserción,
hacer clic en el botón "Cancel".
Cuando se ha llevado a cabo una operación de inserción, el DetailsView
recoge los valores de sus entradas y llena un diccionario de Valores
que se pasará a la fuente de datos. El SqlDataSource aplica estos
valores al grupo de parámetros de InsertCommand antes de ejecutar el
comando. De la misma forma que con las Actualizaciones, la capacidad de
inserción automática recae en parámetros en el InserCommand, que se
llaman exactamente de la misma forma que los campos que se devuelven en
la operación de selección. Observar que el diccionario de Claves no se
requiere para la inserción.