efectuando acceso a datos
TRANSCRIPT
Efectuando Acceso a DatosLo nuevo en 2.0
Controles de Fuente de Datos - ASP.NET 2.0 introduce controles declarativos de fuente de datos que
hacen accesibles los datos de almacenes internos (bases de datos SQL, objetos de negocios de capa
intermedia o ficheros XML) a los controles de la interfaz de usuario (UI), para el enlazado a datos en una
página. Los controles de fuente de datos también tienen otras capacidades como la clasificación, la
paginación, el "catching", la actualización, la inserción y la eliminación de datos, que los controles de la UI
puede aprovechar sin requerir ningún tipo de código.
Nuevos Controles de Enlazado a Datos - Además de los controles de enlazado a datos de ASP.NET
1.x, ASP.NET incluye nuevos controles de UI de enlazado a datos como el GridView, DetailsView,FormView,
TreeView y Menu, que se pueden personalizar para mostrar los datos en diferentes formatos. Los controles
GridView, DetailsView y FormView pueden, además, aprovechar las capacidades de la fuente de datos,
haciendo así más sencillo las operaciones de clasificación, paginación y actualización en páginas orientadas
a datos (data-driven).
Parámetros de Control de Datos - Las fuentes de datos pueden aceptar parámetros de entrada de
diferentes fuentes utilizando los nuevos "objetos de parámetros" de controles de datos de ASP.NET 2.0.
Estos "objetos de parámetros" nos permiten proporcionar fácilmente los valores de las propiedades de los
controles de servidor (campos sesión, aplicación, cookie y querystring) y las propiedades del perfil de
usuario para operaciones de datos parametrizadas. La utilización de estos parámetros permite el filtrado y
escenarios de "master-details" con poco código o código personalizado.
Sintaxis de Enlazado a Datos Mejorada - La sintaxis de enlazado a datos de DataBinder.Eval en
ASP.NET se ha simplificado para el escenario común de enlazar un control en una plantilla enlazada a
datos. Es posible, además, asociar dos formas de enlazar datos con las propiedades de un control en una
plantilla para permitir, de esta forma, que los valores se pasen automáticamente para la actualización,
inserción o borrado en la fuente de datos. Para datos XML jerárquicos ASP.NET 2.0 también incluye una
sintaxis de enlazado a datos basado en XPath.
Bases de Datos de Ficheros Locales Utilizando SQL Express - Para un desarrollo más sencillo,
ASP.NET 2.0 soporta la habilidad de conectar con una base de datos SQL Express como un fichero local de
la aplicación, eliminando la necesidad de enviar la base de datos a un servidor sólo para realizar el trabajo
de desarrollo. Por supuesto, también podemos seguir conectándonos a las bases de datos de un servidor
SQL.
Esta sección describe éstas y otras características del acceso a datos en ASP.NET 2.0.
Prácticamente todas las aplicaciones Web dinámicas realizan algun tipo de acceso a datos y,
afortunadamente, ASP.NET 2.0 facilita mucho esta acción. A diferencia de ASP.NET 1.0, que requería que los
desarrolladores escribieran código personalizado para recuperar y enlazar los datos a controles de servidor,
ASP.NET 2.0 permite una solución declarativa para el enlazado a datos que requiere poco código para los
escenarios de datos más comunes, como por ejemplo:
Seleccionar y Mostrar Datos
Ordenar, Paginar y Cachear Datos
Actualizar, Insertar y Borrar Datos
Filtrar o "Master-Details" Utilizando Parámetros
ASP.NET 2.0 introduce dos tipos de controles de servidor que participan en este modelo declarativo de
enlazado a datos. Estos dos tipos de controles de datos manejan toda la complejidad del modelo Web para
escenarios de datos, de forma que los desarrolladores no tienen que entender los eventos del ciclo de vida de
las peticiones para realizar el enlazado de los datos. Otro beneficio de este modelo basado en controles es que
se puede extender de forma sencilla para soportar el acceso a datos de otros proveedores.
Controles de Fuente de Datos
Los controles de fuente de datos no se representan, sino que, en lugar de eso, representan un almacén de datos, como por ejemplo una base de datos, un objeto de negocio, un fichero XML o un Web Service XML. Los controles de fuente de datos también hacen posibles funconalidades más "ricas" sobre los datos (clasificación, paginación, filtrado, actualización, borrado e inserción) que pueden utilizar los controles de enlazado a datos de la UI de forma automática. ASP.NET incluye los siguientes controles de servidor, por defecto:
Nombre DescripciónSqlDataSource Permite enlazar a una base de datos SQL representada por un proveedor ADO.NET, como por ejemplo
Microsoft™ SQL Server, OLEDB, ODBC, o Oracle.ObjectDataSource Permite enlazar a un objeto de capa intermedia como los de capa de acceso a datos o un componente
de negocios.AccessDataSource Permite enlazar a una base de datos Microsoft™ Access (Jet).SiteMapDataSource Permite enlazar a la jerarquia mostrada por un proveedor de navegación de sites de ASP.NET 2.0.XmlDataSource Permite enlazar a un fichero o documento XML.
Controles de Enlazado de Datos
Los controles de enlazado de datos son controles de UI que renderizan los datos como marcas para los
dispositivos o navegadores clientes. Un control de enlazado de datos puede auto-enlazar una fuente de datos
a un dato mostrado y traerá los datos en el momento apropiado dentro del ciclo de vida de la página. Estos
controles puedes aprovecharse, opcionalmente, de las capacidades de la fuente de datos, como por ejemplo
clasificación, paginación, filtrado, actualizado, borrado y inserción. Un control de enlazado de datos se conecta con una fuente de datos a través de su propiedad DataSourceID. Podemos estar familiarizados con algunos de los controles de enlazado de datos de ASP.NET 1.x, como por ejemplo DataGrid, DataList, Repeater, y controles de lista como DropDownList. ASP.NET 2.0 contiene varios controles de enlazado de datos nuevos, como:
Nombre DescripciónGridView Presenta los datos en formato de "rejilla" (grid). Es una evolución del control DataGrid, y puede aprovechar
automáticamente las características de la fuente de datos.DetailsView Presenta un sólo elemento en una tabla de parejas etiqueta/valor, similar a la vista de formulario de Microsoft™
Access. Este control también puede aprovechar automáticamente las características de la fuente de datos.FormView Presenta de la forma definida en una platilla personalizada un sólo elemento de datos. Presenta un elemento en
una tabla de parejas etiqueta/valor, similar a la vista de formulario de Microsoft™ Access. Este control también puede aprovechar automáticamente las características de la fuente de datos.
TreeView Presenta los datos en una vista de árbol jerárquico de nodos expandibles.Menu Presenta los datos en un menú dinámico expandible (incluyendo flyouts).
Esta sección demuestra éstas y otras características nuevas de ASP.NET 2.0.
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, como Microsoft SQL Server, Oracle, o 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. Se pretende que SqlDataSource reemplace al código ADO.NET que escribiriamos normalmente
para crear una conexión y hacer una petición a una base de datos. 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
Para demostrar como enlazar los datos desde una base de datos, los siguientes ejemplos aprovecharán el
nuevo control de enlazado de datos llamado GridView. Dicho control 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. Si estáis familiarizados
con el control DataGrid de ASP.NET 1.x, el control GridView es el que lo reemplaza y tiene un modelo de objeto
muy similar.
El control GridView soporta las siguientes características:
Vicular 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 primero hay que configurar un SqlDataSource en la
página y después 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 [au_id], [au_lname], [au_fname] 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 Microsoft™ SQL Server.
GridViewSimple_vb.aspx GridView-SqlDataSource
<%@ Page Language="VB" %><html><head runat="server"> <title>GridView Bound to SqlDataSource</title></head><body> <form id="form1" runat="server"> <asp:GridView ID="GridView1" DataSourceID="SqlDataSource1" runat="server" /> <asp:SqlDataSource ID="SqlDataSource1" runat="server" SelectCommand="SELECT [au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract] FROM [authors]" ConnectionString="<%$ ConnectionStrings:Pubs %>" /> </form></body></html>
Web.config
<?xml version="1.0"?><configuration> <connectionStrings> <!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" />
--> <add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> <databases> <add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching> </system.web></configuration>
El control SqlDataSource no se limita a conexiones con bases de datos de Microsoft™ 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 Framewrok .NET.
<configuration>
<system.data>
<DbProviderFactories>
<add name="Odbc Data Provider" invariant="System.Data.Odbc"
type="System.Data.Odbc.OdbcFactory, ..." />
<add name="OleDb Data Provider" invariant="System.Data.OleDb"
type="System.Data.OleDb.OleDbFactory, ..." />
<add name="OracleClient Data Provider" invariant="System.Data.OracleClient"
type="System.Data.OracleClient.OracleClientFactory, ..." />
<add name="SqlClient Data Provider" invariant="System.Data.SqlClient"
type="System.Data.SqlClient.SqlClientFactory, ..." />
</DbProviderFactories>
</system.data>
</configuration>
La propiedad ProviderName de SqlDataSource se puede establecer a un nombre invariante de cualquier
proveedor (por defecto System.Data.SqlClient). Observar que si cambiamos el nombre de proveedor
tendremos que asegurarnos que las propiedades ConnectionString y SelectCommand utilizan la sintaxi
correcta para el proveedor seleccionado.
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.
GridViewBoundFields_vb.aspx
<%@ Page Language="VB" %><html><head runat="server"> <title>GridView Bound Fields</title></head><body> <form id="form1" runat="server"> <asp:GridView ID="GridView1" DataSourceID="SqlDataSource1" AutoGenerateColumns="False" runat="server"> <Columns> <asp:BoundField HeaderText="ID" DataField="au_id" ReadOnly="true" /> <asp:BoundField HeaderText="Last Name" DataField="au_lname" /> <asp:BoundField HeaderText="First Name" DataField="au_fname" /> <asp:BoundField HeaderText="Phone" DataField="phone" /> <asp:BoundField HeaderText="Address" DataField="address" /> <asp:BoundField HeaderText="City" DataField="city" /> <asp:BoundField HeaderText="State" DataField="state" /> <asp:BoundField HeaderText="Zip Code" DataField="zip" /> <asp:CheckBoxField HeaderText="Contract" DataField="contract" /> </Columns> </asp:GridView> <asp:SqlDataSource ID="SqlDataSource1" runat="server" SelectCommand="SELECT [au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract] FROM [authors]" ConnectionString="<%$ ConnectionStrings:Pubs %>" /> </form></body></html>
Web.config
<?xml version="1.0"?><configuration> <connectionStrings> <!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" /> -->
<add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> <databases> <add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching> </system.web></configuration>
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". El siguiente ejemplo muestra el contro SqlDataSource configurado para seleccionar datos de un procedimiento almacenado en la base de datos Northwind.
GridViewStoredProc_vb.aspx (BoundFields)
<%@ Page Language="VB" %><html><head runat="server"> <title>GridView Bound to Stored Procedure</title></head><body> <form id="form1" runat="server"> <asp:GridView ID="GridView1" DataSourceID="SqlDataSource1" AutoGenerateColumns="False" runat="server"> <Columns> <asp:BoundField DataField="TenMostExpensiveProducts" HeaderText="Product" /> <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}" HeaderText="Price" /> </Columns> </asp:GridView> <asp:SqlDataSource ID="SqlDataSource1" runat="server" SelectCommand="Ten Most Expensive Products" ConnectionString="<%$ ConnectionStrings:Northwind %>" SelectCommandType="StoredProcedure" /> </form></body></html>
Web.config
<?xml version="1.0"?><configuration> <connectionStrings> <!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" /> --> <add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> <databases> <add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching> </system.web></configuration>
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". El siguiente ejemplo muestra el contro SqlDataSource configurado
para seleccionar datos de un procedimiento almacenado en la base de datos Northwind.
GridView-SqlDataSource (Procedimiento Almacenado)
GridViewStoredProc_vb.aspx<%@ Page Language="VB" %><html><head runat="server"> <title>GridView Bound to Stored Procedure</title></head><body> <form id="form1" runat="server">
<asp:GridView ID="GridView1" DataSourceID="SqlDataSource1" AutoGenerateColumns="False" runat="server"> <Columns> <asp:BoundField DataField="TenMostExpensiveProducts" HeaderText="Product" /> <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}" HeaderText="Price" /> </Columns> </asp:GridView> <asp:SqlDataSource ID="SqlDataSource1" runat="server" SelectCommand="Ten Most Expensive Products" ConnectionString="<%$ ConnectionStrings:Northwind %>" SelectCommandType="StoredProcedure" /> </form></body></html>
Web.config
<?xml version="1.0"?><configuration> <connectionStrings> <!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" /> --> <add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> <databases> <add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching>
</system.web></configuration>
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. El siguiente ejemplo
muestra el modo DataReades del control SqlDataSource.
GridView-SqlDataSource (DataReader)
GridViewDataReader_vb.aspx
<%@ Page Language="VB" %><html><head runat="server"> <title>GridView Bound to SqlDataReader</title></head><body> <form id="form1" runat="server"> <asp:GridView ID="GridView1" DataSourceID="SqlDataSource1" AutoGenerateColumns="False" runat="server"> <Columns> <asp:BoundField DataField="TenMostExpensiveProducts" HeaderText="Product" /> <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}" HeaderText="Price" /> </Columns> </asp:GridView> <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:Northwind %>" SelectCommand="Ten Most Expensive Products" SelectCommandType="StoredProcedure" DataSourceMode="DataReader" /> </form></body></html>
Web.config
<?xml version="1.0"?><configuration> <connectionStrings> <!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" />
<add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" /> --> <add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> <databases> <add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching> </system.web></configuration>
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>
El siguiente ejemplo muestra el fichero Web.config utilizado por los anteriores ejemplos de SqlDataSource.
Configuración de Cadenas de Conexión
Web.config.strings
<?xml version="1.0"?><configuration> <connectionStrings> <add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" />
<add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> </system.web></configuration>
Almacenar las cadenas de conexión en el fichero Web.config es una práctica recomendada para cualquier
aplicación ASP.NET, no sólo para su administración centralizada, sino para hacer más seguras las cadenas de
conexión. En ASP.NET 2.0 hay disponible una herramienta de linea de comandos para el encriptado de esta
sección para una mayor seguridad en ambientes de producción. Para más de talles sobre el encriptado de
cadenas de conexión acudid a la sección "Encriptado de Secciones de Configuración" de la sección de
administración de este tutorial. El siguiente ejemplo muestra el fichero Web.config con una sección
<connectionStrings/> encriptada.
Configuración de Cadenas de Conexión (Encriptadas)
Web.config.encrypted
<?xml version="1.0"?><configuration> <protectedData> <protectedDataSections> <add name="connectionStrings" provider="RsaProtectedConfigurationProvider" inheritedByChildren="false" /> </protectedDataSections> </protectedData> <connectionStrings> <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns="http://www.w3.org/2001/04/xmlenc#"> <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" /> <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#"> <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" /> <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#"> <KeyName>Rsa Key</KeyName> </KeyInfo> <CipherData> <CipherValue>408EYuABn0MbVxxN9CAHMFpkX36odWkolxVw0neiuBQ888tZbpf8S7TWfpWDC4uz000uhH0FuR3iYVQkbEZ0gEU+y5zDcVp3uVzzryr7P4h/fm1oH0RnDPeKcegAkkq1HaX0tu5c5wcFmIi2Qs4pTR8kjn30kYBfBIUg5AsdZCo=</CipherValue> </CipherData> </EncryptedKey> </KeyInfo> <CipherData> <CipherValue>5lkgSgwPTYDx6OYlRxaSLZhJwhGgssjmtljt+5Fo3hYt+Mu35oN4L4ODoiFKXpL3Kkd5+E+hABZRSJyRQPvwa26+8YGK5tV03xTjMs4rQkTh55514jv85i+bmZjNLmbw41u8QyEYEo30uu2yChdNAjh3TEHuths9nDoqhkTzfn0sx4Hyd2xukFd037c7ZZYrTIsB+EWX9nhFXhC3tTdQrateyiOHiRgyA5tWKXea86u/IUyZhGyC2w3A/PbfJ+oAJHSRAh0YqR+mGlJDcGypwPv7laAXV0VN1H5dFzCgmF5KsUOLyBAMAk/TGPaoXJGsdTjM2zrEzx1/8PITLU/x6IDSN2V53DRn3uHDMoHXBa6n2V3giyxpAitC/
A02qDYPxuuDdPSCS7DALh2FF4FhrcoXQVtKWq+yy3bsQG7wNbQ5b5wCopuoLnjGcPK3BAvyC43krxbyUDBzk8ZIJvo6/FDJn3Uz2mbDquFu80yfM3YyqLV/VFuk6PXQXgF/YcbszKUiBlybSMw5KE2ieWWBiVrWExWayAGw</CipherValue> </CipherData> </EncryptedData> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> </system.web></configuration>
La propiedad ConnectionString del control SqlDataSource se establece a la expresión <%$ ConnectionStrings:Pubs %>, que es traducida por el analizador de ASP.NET al valor de la cadena de
conexión en tiempo de ejecución. También podemos especificar una expresión para la propiedad ProviderName de SqlDataSource, por ejemplo <%$ ConnectionStrings:Pubs.ProviderName %>.
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.
Clasificación del GridView
GridViewSorting_vb.aspx
<%@ Page Language="VB" %><html><head runat="server"> <title>Sorting Data Using GridView</title></head><body> <form id="form1" runat="server">
<asp:GridView ID="GridView1" AllowSorting="true" runat="server" DataSourceID="SqlDataSource1" AutoGenerateColumns="False"> <Columns> <asp:BoundField HeaderText="ID" DataField="au_id" SortExpression="au_id" /> <asp:BoundField HeaderText="Last Name" DataField="au_lname" SortExpression="au_lname" /> <asp:BoundField HeaderText="First Name" DataField="au_fname" SortExpression="au_fname" /> <asp:BoundField HeaderText="Phone" DataField="phone" SortExpression="phone" /> <asp:BoundField HeaderText="Address" DataField="address" SortExpression="address" /> <asp:BoundField HeaderText="City" DataField="city" SortExpression="city" /> <asp:BoundField HeaderText="State" DataField="state" SortExpression="state" /> <asp:BoundField HeaderText="Zip Code" DataField="zip" SortExpression="zip" /> <asp:CheckBoxField HeaderText="Contract" SortExpression="contract" DataField="contract" /> </Columns> </asp:GridView> <asp:SqlDataSource ID="SqlDataSource1" runat="server" SelectCommand="SELECT [au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract] FROM [authors]" ConnectionString="<%$ ConnectionStrings:Pubs %>" /> </form></body></html>
Web.config
<?xml version="1.0"?><configuration> <connectionStrings> <!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" /> --> <add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;"
providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> <databases> <add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching> </system.web></configuration>
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..
Paginación de GridView
GridViewPaging_vb.aspx
<%@ Page Language="VB" %><html><head runat="server"> <title>Paging Data Using GridView</title></head><body> <form id="form1" runat="server"> <asp:GridView ID="GridView1" AllowSorting="true" AllowPaging="true" runat="server" DataSourceID="SqlDataSource1" AutoGenerateColumns="False"> <Columns> <asp:BoundField HeaderText="ID" DataField="au_id" SortExpression="au_id" /> <asp:BoundField HeaderText="Last Name" DataField="au_lname" SortExpression="au_lname" /> <asp:BoundField HeaderText="First Name" DataField="au_fname" SortExpression="au_fname" /> <asp:BoundField HeaderText="Phone" DataField="phone" SortExpression="phone" /> <asp:BoundField HeaderText="Address" DataField="address" SortExpression="address" /> <asp:BoundField HeaderText="City" DataField="city" SortExpression="city" /> <asp:BoundField HeaderText="State" DataField="state" SortExpression="state" /> <asp:BoundField HeaderText="Zip Code" DataField="zip" SortExpression="zip" /> <asp:CheckBoxField HeaderText="Contract" SortExpression="contract" DataField="contract" /> </Columns> </asp:GridView> <asp:SqlDataSource ID="SqlDataSource1" runat="server"
SelectCommand="SELECT [au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract] FROM [authors]" ConnectionString="<%$ ConnectionStrings:Pubs %>" /> </form></body></html>
Web.config
<?xml version="1.0"?><configuration> <connectionStrings> <!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" /> --> <add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> <databases> <add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching> </system.web></configuration>
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.
Ajustes del Paginador de GridView
GridViewPagingSettings_vb.aspx
<%@ Page Language="VB" %><html><head runat="server"> <title>Pager Settings and Styles</title></head><body> <form id="form1" runat="server"> <asp:GridView ID="GridView1" AllowSorting="true" AllowPaging="true" PageSize="3" runat="server" DataSourceID="SqlDataSource1" AutoGenerateColumns="False"> <PagerSettings Mode="NextPreviousFirstLast" Position="TopAndBottom" FirstPageImageUrl="~/Images/First.gif" LastPageImageUrl="~/Images/Last.gif" NextPageImageUrl="~/Images/Next.gif" PreviousPageImageUrl="~/Images/Prev.gif" /> <PagerStyle ForeColor="White" HorizontalAlign="Right" BackColor="#284775" /> <Columns> <asp:BoundField HeaderText="ID" DataField="au_id" SortExpression="au_id" /> <asp:BoundField HeaderText="Last Name" DataField="au_lname" SortExpression="au_lname" /> <asp:BoundField HeaderText="First Name" DataField="au_fname" SortExpression="au_fname" /> <asp:BoundField HeaderText="Phone" DataField="phone" SortExpression="phone" /> <asp:BoundField HeaderText="Address" DataField="address" SortExpression="address" /> <asp:BoundField HeaderText="City" DataField="city" SortExpression="city" /> <asp:BoundField HeaderText="State" DataField="state" SortExpression="state" /> <asp:BoundField HeaderText="Zip Code" DataField="zip" SortExpression="zip" /> <asp:CheckBoxField HeaderText="Contract" SortExpression="contract" DataField="contract" /> </Columns> </asp:GridView> <asp:SqlDataSource ID="SqlDataSource1" runat="server" SelectCommand="SELECT [au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract] FROM [authors]" ConnectionString="<%$ ConnectionStrings:Pubs %>" /> </form></body></html>
Web.config
<?xml version="1.0"?><configuration> <connectionStrings> <!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True"
providerName="System.Data.SqlClient" /> <add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" /> --> <add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> <databases> <add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching> </system.web></configuration>
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 ICollection. 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. El
control ObjectDataSource no soporta esta característica, y de esto se habla en el topic "Clasificación y
Paginación Avanzadas" de este tutorial.
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). Tamnbié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. Se hablará más detalladamente sobre
estas colecciones en los siguientes capítulos.
<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.
Actualización del GridView
GridViewUpdating_vb.aspx
<%@ Page Language="VB" %><html> <head runat="server"> <title>Updating Data Using GridView</title> </head> <body> <form id="form1" runat="server"> <asp:GridView ID="GridView1" AllowSorting="true" AllowPaging="true" Runat="server" DataSourceID="SqlDataSource1" AutoGenerateEditButton="true" DataKeyNames="au_id" AutoGenerateColumns="False"> <Columns> <asp:BoundField ReadOnly="true" HeaderText="ID" DataField="au_id" SortExpression="au_id" /> <asp:BoundField HeaderText="Last Name" DataField="au_lname" SortExpression="au_lname" /> <asp:BoundField HeaderText="First Name" DataField="au_fname" SortExpression="au_fname" /> <asp:BoundField HeaderText="Phone" DataField="phone" SortExpression="phone" /> <asp:BoundField HeaderText="Address" DataField="address" SortExpression="address" /> <asp:BoundField HeaderText="City" DataField="city" SortExpression="city" /> <asp:BoundField HeaderText="State" DataField="state" SortExpression="state" /> <asp:BoundField HeaderText="Zip Code" DataField="zip" SortExpression="zip" /> <asp:CheckBoxField HeaderText="Contract" SortExpression="contract" DataField="contract" />
</Columns> </asp:GridView> <asp:SqlDataSource ID="SqlDataSource1" Runat="server" SelectCommand="SELECT [au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract] FROM [authors]" UpdateCommand="UPDATE [authors] SET [au_lname] = @au_lname, [au_fname] = @au_fname, [phone] = @phone, [address] = @address, [city] = @city, [state] = @state, [zip] = @zip, [contract] = @contract WHERE [au_id] = @au_id" ConnectionString="<%$ ConnectionStrings:Pubs %>" /> </form> </body></html>
Web.config
<?xml version="1.0"?><configuration> <connectionStrings> <!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" /> --> <add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> <databases> <add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching> </system.web></configuration>
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:
1. Cancelar el enlace de datos en el Page_Load si la consulta es un postback
2. Manejar el evento SelectedIndexChanged
3. Añadir el SelectedValue de la DropDownList a la colección de Parámetros de los comandos
4. 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>
El siguiente ejemplo nos muestra un QueryStringUtilizado para obtener un valor paramétrico del querystring
del URL de consulta:
Filtrado por QueryString
GridViewQueryString_vb.aspx<%@ Page Language="VB" %><html> <head runat="server"> <title>Filtering Data In A GridView Using a QueryString</title> </head> <body> <form id="form1" runat="server"> <h4>Enter a query string on the URL, for example: GridViewQueryString_vb.aspx?state=IN</h4>
<asp:GridView ID="GridView1" AllowSorting="True" AllowPaging="True" Runat="server" DataSourceID="SqlDataSource1" AutoGenerateEditButton="True" DataKeyNames="au_id" AutoGenerateColumns="False"> <Columns> <asp:BoundField ReadOnly="true" HeaderText="ID" DataField="au_id" SortExpression="au_id" /> <asp:BoundField HeaderText="Last Name" DataField="au_lname" SortExpression="au_lname" /> <asp:BoundField HeaderText="First Name" DataField="au_fname" SortExpression="au_fname" /> <asp:BoundField HeaderText="Phone" DataField="phone" SortExpression="phone" /> <asp:BoundField HeaderText="Address" DataField="address" SortExpression="address" /> <asp:BoundField HeaderText="City" DataField="city" SortExpression="city" /> <asp:BoundField HeaderText="State" DataField="state" SortExpression="state" /> <asp:BoundField HeaderText="Zip Code" DataField="zip" SortExpression="zip" /> <asp:CheckBoxField HeaderText="Contract" SortExpression="contract" DataField="contract" /> </Columns> </asp:GridView> <asp:SqlDataSource ID="SqlDataSource1" Runat="server" SelectCommand="SELECT [au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract] FROM [authors] WHERE [state] = @state" UpdateCommand="UPDATE [authors] SET [au_lname] = @au_lname, [au_fname] = @au_fname, [phone] = @phone, [address] = @address, [city] = @city, [state] = @state, [zip] = @zip, [contract] = @contract WHERE [au_id] = @au_id" ConnectionString="<%$ ConnectionStrings:Pubs %>"> <SelectParameters> <asp:QueryStringParameter Name="state" QueryStringField="state" DefaultValue="CA" /> </SelectParameters> <UpdateParameters> <asp:Parameter Name="au_lname" /> <asp:Parameter Name="au_fname" /> <asp:Parameter Name="phone" /> <asp:Parameter Name="address" /> <asp:Parameter Name="city" /> <asp:Parameter Name="state" /> <asp:Parameter Name="zip" /> <asp:Parameter Name="contract" /> <asp:Parameter Name="au_id" /> </UpdateParameters> </asp:SqlDataSource> </form> </body></html>
Web.config
<?xml version="1.0"?>
<configuration> <connectionStrings> <!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" /> --> <add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> <databases> <add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching> </system.web></configuration>
El siguiente ejemplo nos muestra como un ControlParameter se usa para obtener el valor de un parámetro de
un control DropDownList de la página:
Filtrado por DropDownList
GridViewDropDownList_vb.aspx
<%@ Page Language="VB" %><html> <head runat="server"> <title>Filtering Data In A GridView Using a DropDownList</title> </head> <body> <form id="form1" runat="server"> <b>Choose a state:</b> <asp:DropDownList ID="DropDownList1" DataSourceID="SqlDataSource2" AutoPostBack="true" DataTextField="state" Runat="server" /> <asp:SqlDataSource ID="SqlDataSource2" Runat="server" SelectCommand="SELECT DISTINCT [state] FROM [authors]" ConnectionString="<%$ ConnectionStrings:Pubs %>" />
<br /> <br /> <asp:GridView ID="GridView1" AllowSorting="True" AllowPaging="True" Runat="server" DataSourceID="SqlDataSource1" AutoGenerateEditButton="True" DataKeyNames="au_id" AutoGenerateColumns="False"> <Columns> <asp:BoundField ReadOnly="true" HeaderText="ID" DataField="au_id" SortExpression="au_id" /> <asp:BoundField HeaderText="Last Name" DataField="au_lname" SortExpression="au_lname" /> <asp:BoundField HeaderText="First Name" DataField="au_fname" SortExpression="au_fname" /> <asp:BoundField HeaderText="Phone" DataField="phone" SortExpression="phone" /> <asp:BoundField HeaderText="Address" DataField="address" SortExpression="address" /> <asp:BoundField HeaderText="City" DataField="city" SortExpression="city" /> <asp:BoundField HeaderText="State" DataField="state" SortExpression="state" /> <asp:BoundField HeaderText="Zip Code" DataField="zip" SortExpression="zip" /> <asp:CheckBoxField HeaderText="Contract" SortExpression="contract" DataField="contract" /> </Columns> </asp:GridView> <asp:SqlDataSource ID="SqlDataSource1" Runat="server" SelectCommand="SELECT [au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract] FROM [authors] WHERE [state] = @state" UpdateCommand="UPDATE [authors] SET [au_lname] = @au_lname, [au_fname] = @au_fname, [phone] = @phone, [address] = @address, [city] = @city, [state] = @state, [zip] = @zip, [contract] = @contract WHERE [au_id] = @au_id" ConnectionString="<%$ ConnectionStrings:Pubs %>"> <SelectParameters> <asp:ControlParameter Name="state" ControlID="DropDownList1" /> </SelectParameters> <UpdateParameters> <asp:Parameter Name="au_lname" /> <asp:Parameter Name="au_fname" /> <asp:Parameter Name="phone" /> <asp:Parameter Name="address" /> <asp:Parameter Name="city" /> <asp:Parameter Name="state" /> <asp:Parameter Name="zip" /> <asp:Parameter Name="contract" /> <asp:Parameter Name="au_id" /> </UpdateParameters> </asp:SqlDataSource> </form> </body></html>
Web.config
<?xml version="1.0"?><configuration> <connectionStrings> <!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" /> --> <add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> <databases> <add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching> </system.web></configuration>
Podemos configurar los parámetros de datos para devolver valores de cualquiera de las siguientes fuentes:
Nombre Descripción
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 Namecomú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.
El siguiente ejemplo muestra el cacheo mediante el control SqlDataSource. La columna TimeStamp se
actualiza en cada petición, de forma que podemos ver la asiduidad con la que los datos se cogen de la base de
datos frente a los que se piden de la caché. Observar que aproximádamente cada 5 segundos se actualiza el
TimeStamp.
"Caheando" SqlDataSource
GridViewCaching_vb.aspx
<%@ Page Language="VB" %><html> <head runat="server"> <title>Caching Data</title> </head> <body> <form id="form1" runat="server"> <b>Choose a state:</b> <asp:DropDownList ID="DropDownList1" DataSourceID="SqlDataSource2" AutoPostBack="true" DataTextField="state" Runat="server" /> <asp:SqlDataSource ID="SqlDataSource2" Runat="server" SelectCommand="SELECT DISTINCT [state] FROM [authors]"
ConnectionString="<%$ ConnectionStrings:Pubs %>" /> <br /> <br /> <asp:GridView ID="GridView1" AllowSorting="True" AllowPaging="True" Runat="server" DataSourceID="SqlDataSource1" AutoGenerateEditButton="True" DataKeyNames="au_id" AutoGenerateColumns="False"> <Columns> <asp:BoundField DataField="TimeStamp" HeaderText="TimeStamp" ReadOnly="True"> <ItemStyle Font-Bold="True" /> </asp:BoundField> <asp:BoundField ReadOnly="True" HeaderText="ID" DataField="au_id" SortExpression="au_id" /> <asp:BoundField HeaderText="Last Name" DataField="au_lname" SortExpression="au_lname" /> <asp:BoundField HeaderText="First Name" DataField="au_fname" SortExpression="au_fname" /> <asp:BoundField HeaderText="Phone" DataField="phone" SortExpression="phone" /> <asp:BoundField HeaderText="Address" DataField="address" SortExpression="address" /> <asp:BoundField HeaderText="City" DataField="city" SortExpression="city" /> <asp:BoundField HeaderText="State" DataField="state" SortExpression="state" /> <asp:BoundField HeaderText="Zip Code" DataField="zip" SortExpression="zip" /> <asp:CheckBoxField HeaderText="Contract" SortExpression="contract" DataField="contract" /> </Columns> </asp:GridView> <asp:SqlDataSource ID="SqlDataSource1" Runat="server" SelectCommand="SELECT DatePart(second, GetDate()) As TimeStamp, [au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract] FROM [authors] WHERE [state] = @state" UpdateCommand="UPDATE [authors] SET [au_lname] = @au_lname, [au_fname] = @au_fname, [phone] = @phone, [address] = @address, [city] = @city, [state] = @state, [zip] = @zip, [contract] = @contract WHERE [au_id] = @au_id" ConnectionString="<%$ ConnectionStrings:Pubs %>" CacheDuration="5" EnableCaching="True"> <SelectParameters> <asp:ControlParameter Name="state" ControlID="DropDownList1" /> </SelectParameters> <UpdateParameters> <asp:Parameter Name="au_lname" /> <asp:Parameter Name="au_fname" /> <asp:Parameter Name="phone" /> <asp:Parameter Name="address" /> <asp:Parameter Name="city" /> <asp:Parameter Name="state" /> <asp:Parameter Name="zip" /> <asp:Parameter Name="contract" /> <asp:Parameter Name="au_id" /> </UpdateParameters> </asp:SqlDataSource>
</form> </body></html>Web.config
<?xml version="1.0"?><configuration> <connectionStrings> <!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" /> --> <add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> <databases> <add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching> </system.web></configuration>
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 siguiente ejemplo muestra esta técnica de filtrado en acción:
Filtrando Entradas de Caché
GridViewCachingFilter_vb.aspx
<%@ Page Language="VB" %><html> <head runat="server"> <title>Filtering Cached Data</title> </head> <body> <form id="form1" runat="server"> <b>Choose a state:</b> <asp:DropDownList ID="DropDownList1" DataSourceID="SqlDataSource2" AutoPostBack="true" DataTextField="state" Runat="server" /> <asp:SqlDataSource ID="SqlDataSource2" Runat="server" SelectCommand="SELECT DISTINCT [state] FROM [authors]" ConnectionString="<%$ ConnectionStrings:Pubs %>" /> <br /> <br /> <asp:GridView ID="GridView1" AllowSorting="True" AllowPaging="True" Runat="server" DataSourceID="SqlDataSource1" AutoGenerateEditButton="True" DataKeyNames="au_id" AutoGenerateColumns="False"> <Columns> <asp:BoundField DataField="TimeStamp" HeaderText="TimeStamp" ReadOnly="True"> <ItemStyle Font-Bold="True" /> </asp:BoundField> <asp:BoundField ReadOnly="True" HeaderText="ID" DataField="au_id" SortExpression="au_id" />
<asp:BoundField HeaderText="Last Name" DataField="au_lname" SortExpression="au_lname" /> <asp:BoundField HeaderText="First Name" DataField="au_fname" SortExpression="au_fname" /> <asp:BoundField HeaderText="Phone" DataField="phone" SortExpression="phone" /> <asp:BoundField HeaderText="Address" DataField="address" SortExpression="address" /> <asp:BoundField HeaderText="City" DataField="city" SortExpression="city" /> <asp:BoundField HeaderText="State" DataField="state" SortExpression="state" /> <asp:BoundField HeaderText="Zip Code" DataField="zip" SortExpression="zip" /> <asp:CheckBoxField HeaderText="Contract" SortExpression="contract" DataField="contract" /> </Columns> </asp:GridView> <asp:SqlDataSource ID="SqlDataSource1" Runat="server" SelectCommand="SELECT DatePart(second, GetDate()) As TimeStamp, [au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract] FROM [authors]" UpdateCommand="UPDATE [authors] SET [au_lname] = @au_lname, [au_fname] = @au_fname, [phone] = @phone, [address] = @address, [city] = @city, [state] = @state, [zip] = @zip, [contract] = @contract WHERE [au_id] = @au_id" ConnectionString="<%$ ConnectionStrings:Pubs %>" CacheDuration="5" EnableCaching="True" FilterExpression="state='{0}'"> <UpdateParameters> <asp:Parameter Name="au_lname" /> <asp:Parameter Name="au_fname" /> <asp:Parameter Name="phone" /> <asp:Parameter Name="address" /> <asp:Parameter Name="city" /> <asp:Parameter Name="state" /> <asp:Parameter Name="zip" /> <asp:Parameter Name="contract" /> <asp:Parameter Name="au_id" /> </UpdateParameters> <FilterParameters> <asp:ControlParameter ControlID="DropDownList1" Name="state" PropertyName="SelectedValue" /> </FilterParameters> </asp:SqlDataSource> </form> </body></html>Web.config
<?xml version="1.0"?><configuration> <connectionStrings> <!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" />
<add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" /> --> <add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> <databases> <add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching> </system.web></configuration>
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".
En este ejemplo, fijamos el CacheDuration a "Infinite" y especificamos SqlCacheDependency. Observar que la
columna TimeStamp no se actualiza hasta que los datos se modifican mediante el botón "Edit" del GridView.
SqlCacheInvalidation de la Fuente de Datos
GridViewCachingSql_vb.aspx
<%@ Page Language="VB" %><html> <head runat="server"> <title>Data Sources and SqlCacheInvalidation</title> </head> <body> <form id="form1" runat="server"> <b>Choose a state:</b> <asp:DropDownList ID="DropDownList1" DataSourceID="SqlDataSource2" AutoPostBack="true" DataTextField="state" Runat="server" /> <asp:SqlDataSource ID="SqlDataSource2" Runat="server" SelectCommand="SELECT DISTINCT [state] FROM [authors]" ConnectionString="<%$ ConnectionStrings:Pubs %>" /> <br /> <br /> <asp:GridView ID="GridView1" AllowSorting="True" AllowPaging="True" Runat="server" DataSourceID="SqlDataSource1" AutoGenerateEditButton="True" DataKeyNames="au_id" AutoGenerateColumns="False"> <Columns> <asp:BoundField DataField="TimeStamp" HeaderText="TimeStamp" ReadOnly="True"> <ItemStyle Font-Bold="True" /> </asp:BoundField> <asp:BoundField ReadOnly="True" HeaderText="ID" DataField="au_id" SortExpression="au_id" /> <asp:BoundField HeaderText="Last Name" DataField="au_lname" SortExpression="au_lname" /> <asp:BoundField HeaderText="First Name" DataField="au_fname" SortExpression="au_fname" /> <asp:BoundField HeaderText="Phone" DataField="phone" SortExpression="phone" /> <asp:BoundField HeaderText="Address" DataField="address" SortExpression="address" /> <asp:BoundField HeaderText="City" DataField="city" SortExpression="city" /> <asp:BoundField HeaderText="State" DataField="state" SortExpression="state" /> <asp:BoundField HeaderText="Zip Code" DataField="zip" SortExpression="zip" /> <asp:CheckBoxField HeaderText="Contract" SortExpression="contract" DataField="contract" /> </Columns> </asp:GridView> <asp:SqlDataSource ID="SqlDataSource1" Runat="server" SelectCommand="SELECT DatePart(second, GetDate()) As TimeStamp, [au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract] FROM [authors]"
UpdateCommand="UPDATE [authors] SET [au_lname] = @au_lname, [au_fname] = @au_fname, [phone] = @phone, [address] = @address, [city] = @city, [state] = @state, [zip] = @zip, [contract] = @contract WHERE [au_id] = @au_id" ConnectionString="<%$ ConnectionStrings:Pubs %>" EnableCaching="True" FilterExpression="state='{0}'" SqlCacheDependency="Pubs:Authors"> <UpdateParameters> <asp:Parameter Name="au_lname" /> <asp:Parameter Name="au_fname" /> <asp:Parameter Name="phone" /> <asp:Parameter Name="address" /> <asp:Parameter Name="city" /> <asp:Parameter Name="state" /> <asp:Parameter Name="zip" /> <asp:Parameter Name="contract" /> <asp:Parameter Name="au_id" /> </UpdateParameters> <FilterParameters> <asp:ControlParameter ControlID="DropDownList1" Name="state" PropertyName="SelectedValue" /> </FilterParameters> </asp:SqlDataSource> </form> </body></html>
Web.config
<?xml version="1.0"?><configuration> <connectionStrings> <!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" /> --> <add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching>
<sqlCacheDependency enabled="true" pollTime="1000"> <databases> <add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching> </system.web></configuration>
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).
Master-Details w/ GridView and DetailsView
GridViewMasterDetails_vb.aspx
<%@ Page Language="VB" %><html><head runat="server"> <title>GridView DetailsView Master-Details (1 Page)</title></head><body> <form id="form1" runat="server"> <b>Choose a state:</b> <asp:DropDownList ID="DropDownList1" DataSourceID="SqlDataSource2" AutoPostBack="true" DataTextField="state" runat="server" />
<asp:SqlDataSource ID="SqlDataSource2" runat="server" SelectCommand="SELECT DISTINCT [state] FROM [authors]" ConnectionString="<%$ ConnectionStrings:Pubs %>" /> <br /> <br /> <table> <tr> <td valign="top"> <asp:GridView ID="GridView1" AllowSorting="True" AllowPaging="True" runat="server" DataSourceID="SqlDataSource1" DataKeyNames="au_id" AutoGenerateColumns="False" Width="427px"> <Columns> <asp:CommandField ShowSelectButton="True" /> <asp:BoundField DataField="au_id" HeaderText="au_id" ReadOnly="True" SortExpression="au_id" /> <asp:BoundField DataField="au_lname" HeaderText="au_lname" SortExpression="au_lname" /> <asp:BoundField DataField="au_fname" HeaderText="au_fname" SortExpression="au_fname" /> <asp:BoundField DataField="state" HeaderText="state" SortExpression="state" /> </Columns> </asp:GridView> <asp:SqlDataSource ID="SqlDataSource1" runat="server" SelectCommand="SELECT [au_id], [au_lname], [au_fname], [state] FROM [authors] WHERE ([state] = @state)" ConnectionString="<%$ ConnectionStrings:Pubs %>"> <SelectParameters> <asp:ControlParameter ControlID="DropDownList1" Name="state" PropertyName="SelectedValue" Type="String" /> </SelectParameters> </asp:SqlDataSource> </td> <td valign="top"> <asp:DetailsView AutoGenerateRows="False" DataKeyNames="au_id" DataSourceID="SqlDataSource3" HeaderText="Author Details" ID="DetailsView1" runat="server" Width="275px"> <Fields> <asp:BoundField DataField="au_id" HeaderText="au_id" ReadOnly="True" SortExpression="au_id" /> <asp:BoundField DataField="au_lname" HeaderText="au_lname" SortExpression="au_lname" /> <asp:BoundField DataField="au_fname" HeaderText="au_fname" SortExpression="au_fname" /> <asp:BoundField DataField="phone" HeaderText="phone" SortExpression="phone" /> <asp:BoundField DataField="address" HeaderText="address" SortExpression="address" /> <asp:BoundField DataField="city" HeaderText="city" SortExpression="city" /> <asp:BoundField DataField="state" HeaderText="state" SortExpression="state" /> <asp:BoundField DataField="zip" HeaderText="zip" SortExpression="zip" />
<asp:CheckBoxField DataField="contract" HeaderText="contract" SortExpression="contract" /> </Fields> </asp:DetailsView> <asp:SqlDataSource ConnectionString="<%$ ConnectionStrings:Pubs %>" ID="SqlDataSource3" runat="server" SelectCommand="SELECT [au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract] FROM [authors] WHERE ([au_id] = @au_id)"> <SelectParameters> <asp:ControlParameter ControlID="GridView1" Name="au_id" PropertyName="SelectedValue" Type="String" /> </SelectParameters> </asp:SqlDataSource> </td> </tr> </table> <br /> </form></body></html>
Web.config
<?xml version="1.0"?><configuration> <connectionStrings> <!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" /> --> <add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> <databases>
<add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching> </system.web></configuration>
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). El siguiente ejemplo demuestra un
DetailsView configurado para soportar la edición de registros en un escenario de master-details.
Edición de DetailsView
GridViewMasterDetailsEdit_vb.aspx
<%@ Page Language="VB" %><html><head id="Head1" runat="server"> <title>GridView DetailsView Master-Details (with Editing)</title></head><script runat="server">
Protected Sub DetailsView1_ItemUpdated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DetailsViewUpdatedEventArgs) GridView1.DataBind() DropDownList1.DataBind() End Sub
Protected Sub GridView1_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs) DetailsView1.ChangeMode(DetailsViewMode.ReadOnly) End Sub
Protected Sub GridView1_Sorted(ByVal sender As Object, ByVal a As EventArgs) DetailsView1.ChangeMode(DetailsViewMode.ReadOnly) End Sub
Protected Sub DropDownList1_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs) DetailsView1.ChangeMode(DetailsViewMode.ReadOnly) End Sub Protected Sub GridView1_PageIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) DetailsView1.ChangeMode(DetailsViewMode.ReadOnly) End Sub
</script><body> <form id="form1" runat="server"> <b>Choose a state:</b>
<asp:DropDownList ID="DropDownList1" DataSourceID="SqlDataSource2" AutoPostBack="true" DataTextField="state" runat="server" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged" /> <asp:SqlDataSource ID="SqlDataSource2" runat="server" SelectCommand="SELECT DISTINCT [state] FROM [authors]" ConnectionString="<%$ ConnectionStrings:Pubs %>" /> <br /> <br /> <table> <tr> <td valign="top"> <asp:GridView ID="GridView1" AllowSorting="True" AllowPaging="True" runat="server" DataSourceID="SqlDataSource1" DataKeyNames="au_id" AutoGenerateColumns="False" Width="427px" OnSelectedIndexChanged="GridView1_SelectedIndexChanged" OnSorted="GridView1_Sorted" OnPageIndexChanged="GridView1_PageIndexChanged"> <Columns> <asp:CommandField ShowSelectButton="True" /> <asp:BoundField DataField="au_id" HeaderText="au_id" ReadOnly="True" SortExpression="au_id" /> <asp:BoundField DataField="au_lname" HeaderText="au_lname" SortExpression="au_lname" /> <asp:BoundField DataField="au_fname" HeaderText="au_fname" SortExpression="au_fname" /> <asp:BoundField DataField="state" HeaderText="state" SortExpression="state" /> </Columns> </asp:GridView> <asp:SqlDataSource ID="SqlDataSource1" runat="server" SelectCommand="SELECT [au_id], [au_lname], [au_fname], [state] FROM [authors] WHERE ([state] = @state)" ConnectionString="<%$ ConnectionStrings:Pubs %>"> <SelectParameters> <asp:ControlParameter ControlID="DropDownList1" Name="state" PropertyName="SelectedValue" Type="String" /> </SelectParameters> </asp:SqlDataSource> </td> <td valign="top"> <asp:DetailsView AutoGenerateRows="False" DataKeyNames="au_id" OnItemUpdated="DetailsView1_ItemUpdated" DataSourceID="SqlDataSource3" HeaderText="Author Details" ID="DetailsView1" runat="server" Width="275px"> <Fields> <asp:BoundField DataField="au_id" HeaderText="au_id" ReadOnly="True" SortExpression="au_id" /> <asp:BoundField DataField="au_lname" HeaderText="au_lname" SortExpression="au_lname" /> <asp:BoundField DataField="au_fname" HeaderText="au_fname" SortExpression="au_fname" /> <asp:BoundField DataField="phone" HeaderText="phone" SortExpression="phone" /> <asp:BoundField DataField="address" HeaderText="address" SortExpression="address" />
<asp:BoundField DataField="city" HeaderText="city" SortExpression="city" /> <asp:BoundField DataField="state" HeaderText="state" SortExpression="state" /> <asp:BoundField DataField="zip" HeaderText="zip" SortExpression="zip" /> <asp:CheckBoxField DataField="contract" HeaderText="contract" SortExpression="contract" /> <asp:CommandField ShowEditButton="True" /> </Fields> </asp:DetailsView> <asp:SqlDataSource ID="SqlDataSource3" runat="server" ConnectionString="<%$ ConnectionStrings:Pubs %>" SelectCommand="SELECT [au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract] FROM [authors] WHERE ([au_id] = @au_id)" UpdateCommand="UPDATE [authors] SET [au_lname] = @au_lname, [au_fname] = @au_fname, [phone] = @phone, [address] = @address, [city] = @city, [state] = @state, [zip] = @zip, [contract] = @contract WHERE [au_id] = @au_id"> <SelectParameters> <asp:ControlParameter ControlID="GridView1" Name="au_id" PropertyName="SelectedValue" Type="String" /> </SelectParameters> <UpdateParameters> <asp:Parameter Name="au_lname" Type="String" /> <asp:Parameter Name="au_fname" Type="String" /> <asp:Parameter Name="phone" Type="String" /> <asp:Parameter Name="address" Type="String" /> <asp:Parameter Name="city" Type="String" /> <asp:Parameter Name="state" Type="String" /> <asp:Parameter Name="zip" Type="String" /> <asp:Parameter Name="contract" Type="Boolean" /> <asp:Parameter Name="au_id" Type="String" /> </UpdateParameters> </asp:SqlDataSource> </td> </tr> </table> <br /> </form></body></html>
Web.config
<?xml version="1.0"?><configuration> <connectionStrings> <!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" />
<add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" /> --> <add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> <databases> <add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching> </system.web></configuration>
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.
Este ejemplo muestra un escenario master-details utilizando GridVIew y DetailsVIew en páginas separadas. A
diferencia de los ejemplos anteriores, qué mostraban el GridView y el DetailsView enlaados a el mismo tipo de
registro (un "author"), este ejemplo muestra diferentes tipos de registros para los controles "master" y
"details" ("author" y "books"), saociados por relaciones clave externas en la base de datos. Debido a que un
registro de un autor puede tener más de un libro asociado, se ha configurado el DetailsView para soportar
paginación en los registros de libros, en la página de detalles.
Master-Details (Páginas Separadas)
GridViewMasterDetailsPage_vb.aspx
<%@ Page Language="VB" %><html> <head runat="server"> <title>GridView DetailsView Master-Details (2 Page)</title> </head> <body> <form id="form1" runat="server"> <b>Choose a state:</b> <asp:DropDownList ID="DropDownList1" DataSourceID="SqlDataSource2" AutoPostBack="true" DataTextField="state" Runat="server" /> <asp:SqlDataSource ID="SqlDataSource2" Runat="server" SelectCommand="SELECT DISTINCT [state] FROM [authors]" ConnectionString="<%$ ConnectionStrings:Pubs %>" /> <br /> <br /> <asp:GridView ID="GridView1" AllowSorting="True" AllowPaging="True" Runat="server" DataSourceID="SqlDataSource1" DataKeyNames="au_id" AutoGenerateColumns="False"> <Columns> <asp:BoundField ReadOnly="true" HeaderText="ID" DataField="au_id" SortExpression="au_id" /> <asp:BoundField HeaderText="Last Name" DataField="au_lname" SortExpression="au_lname" /> <asp:BoundField HeaderText="First Name" DataField="au_fname" SortExpression="au_fname" /> <asp:BoundField HeaderText="Phone" DataField="phone" SortExpression="phone" /> <asp:BoundField HeaderText="Address" DataField="address" SortExpression="address" /> <asp:BoundField HeaderText="City" DataField="city" SortExpression="city" /> <asp:BoundField HeaderText="State" DataField="state" SortExpression="state" /> <asp:BoundField HeaderText="Zip Code" DataField="zip" SortExpression="zip" /> <asp:CheckBoxField HeaderText="Contract" SortExpression="contract" DataField="contract" /> <asp:HyperLinkField HeaderText="View Details..." Text="View Details..." DataNavigateUrlFields="au_id" DataNavigateUrlFormatString="DetailsView_vb.aspx?ID={0}" /> </Columns> </asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1" Runat="server" SelectCommand="SELECT [au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract] FROM [authors] WHERE [state] = @state" ConnectionString="<%$ ConnectionStrings:Pubs %>"> <SelectParameters> <asp:ControlParameter Name="state" ControlID="DropDownList1" /> </SelectParameters> </asp:SqlDataSource> </form> </body></html>
DetailsView_vb.aspx
<%@ Page Language="VB" %><html> <head runat="server"> <title>DetailsView</title>
</head> <body> <form id="form1" runat="server"> <asp:DetailsView ID="DetailsView1" Runat="server" DataSourceID="SqlDataSource1" AutoGenerateRows="False" HeaderText="Books for Author" AllowPaging="True"> <Fields> <asp:BoundField HeaderText="au_id" DataField="au_id" SortExpression="au_id" /> <asp:BoundField HeaderText="title_id" DataField="title_id" SortExpression="title_id" /> <asp:BoundField HeaderText="title" DataField="title" SortExpression="title" /> <asp:BoundField HeaderText="type" DataField="type" SortExpression="type" /> <asp:BoundField HeaderText="price" DataField="price" SortExpression="price" /> <asp:BoundField HeaderText="notes" DataField="notes" SortExpression="notes" /> </Fields> </asp:DetailsView> <asp:SqlDataSource ID="SqlDataSource1" Runat="server" SelectCommand="SELECT dbo.authors.au_id, dbo.titles.title_id, dbo.titles.title, dbo.titles.type, dbo.titles.price, dbo.titles.notes FROM dbo.authors INNER JOIN dbo.titleauthor ON dbo.authors.au_id = dbo.titleauthor.au_id INNER JOIN dbo.titles ON dbo.titleauthor.title_id = dbo.titles.title_id WHERE (dbo.authors.au_id = @au_id)" ConnectionString="<%$ ConnectionStrings:Pubs %>"> <SelectParameters> <asp:QueryStringParameter Name="au_id" DefaultValue="213-46-8915" QueryStringField="ID" /> </SelectParameters> </asp:SqlDataSource> </form> </body></html>
Web.config
<?xml version="1.0"?><configuration> <connectionStrings> <!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" /> --> <add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> <databases> <add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching> </system.web></configuration>
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.
Podemos emparejar de forma sencilla un DetailsView con un GridView para permitir que se vean los registros
de inserción en el 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 llamn
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.
Inserción en Master-Details
GridViewMasterDetailsInsert_vb.aspx
<%@ Page Language="VB" %><script runat="server">
Protected Sub DetailsView1_ItemInserted(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DetailsViewInsertedEventArgs) If (Not e.Exception Is Nothing) Then
ErrorMessageLabel.Text = "An error occured while entering this record. Please verify you have entered data in the correct format." e.ExceptionHandled = True End If GridView1.DataBind() End Sub
Protected Sub DetailsView1_ItemUpdated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DetailsViewUpdatedEventArgs) GridView1.DataBind() End Sub
Protected Sub DropDownList1_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs) DetailsView1.ChangeMode(DetailsViewMode.ReadOnly) End Sub
Protected Sub GridView1_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs) DetailsView1.ChangeMode(DetailsViewMode.ReadOnly) End Sub
Protected Sub GridView1_PageIndexChanged(ByVal sender As Object, ByVal e As EventArgs) DetailsView1.ChangeMode(DetailsViewMode.ReadOnly) End Sub
Protected Sub GridView1_Sorted(ByVal sender As Object, ByVal e As System.EventArgs) DetailsView1.ChangeMode(DetailsViewMode.ReadOnly) End Sub Protected Sub GridView1_RowDeleted(ByVal sender As Object, ByVal e As GridViewDeletedEventArgs) If (Not e.Exception Is Nothing) Then ErrorMessageLabel.Text = "Failed to DELETE due to foreign key contstraint on the table. You may only delete rows which have no related records." e.ExceptionHandled = True End If End Sub
Protected Sub DetailsView1_DataBound(ByVal sender As Object, ByVal e As EventArgs) If (DetailsView1.CurrentMode = DetailsViewMode.Insert) Then Dim stateTextBox As TextBox = CType(DetailsView1.Rows(6).Cells(1).Controls(0), TextBox) stateTextBox.Text = DropDownList1.SelectedValue stateTextBox.Enabled = False End If End Sub
</script><html><head id="Head1" runat="server"> <title>GridView DetailsView Master-Details (Insert)</title></head><body> <form id="form1" runat="server"> <b>Choose a state:</b> <asp:DropDownList ID="DropDownList1" DataSourceID="SqlDataSource2" AutoPostBack="true" DataTextField="state" runat="server" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged" /> <asp:SqlDataSource ID="SqlDataSource2" runat="server" SelectCommand="SELECT DISTINCT [state] FROM [authors]" ConnectionString="<%$ ConnectionStrings:Pubs %>" /> <br /> <br /> <table> <tr> <td valign="top"> <asp:GridView ID="GridView1" AllowSorting="True" AllowPaging="True" runat="server" DataSourceID="SqlDataSource1" DataKeyNames="au_id"
AutoGenerateColumns="False" Width="500px" SelectedIndex="0" OnSelectedIndexChanged="GridView1_SelectedIndexChanged" OnPageIndexChanged="GridView1_PageIndexChanged" OnRowDeleted="GridView1_RowDeleted" OnSorted="GridView1_Sorted"> <Columns> <asp:CommandField ShowSelectButton="true" ShowDeleteButton="true" /> <asp:BoundField DataField="au_id" HeaderText="au_id" ReadOnly="True" SortExpression="au_id" /> <asp:BoundField DataField="au_lname" HeaderText="au_lname" SortExpression="au_lname" /> <asp:BoundField DataField="au_fname" HeaderText="au_fname" SortExpression="au_fname" /> <asp:BoundField DataField="state" HeaderText="state" SortExpression="state" /> </Columns> </asp:GridView> <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:Pubs %>" SelectCommand="SELECT [au_id], [au_lname], [au_fname], [state] FROM [authors] WHERE ([state] = @state)" DeleteCommand="DELETE FROM [authors] WHERE [au_id] = @au_id"> <SelectParameters> <asp:ControlParameter ControlID="DropDownList1" Name="state" PropertyName="SelectedValue" Type="String" /> </SelectParameters> </asp:SqlDataSource> </td> <td valign="top"> <asp:DetailsView AutoGenerateRows="False" DataKeyNames="au_id" DataSourceID="SqlDataSource3" HeaderText="Author Details" ID="DetailsView1" runat="server" Width="275px" OnItemUpdated="DetailsView1_ItemUpdated" OnItemInserted="DetailsView1_ItemInserted" OnDataBound="DetailsView1_DataBound"> <Fields> <asp:BoundField DataField="au_id" HeaderText="au_id" ReadOnly="True" SortExpression="au_id" /> <asp:BoundField DataField="au_lname" HeaderText="au_lname" SortExpression="au_lname" /> <asp:BoundField DataField="au_fname" HeaderText="au_fname" SortExpression="au_fname" /> <asp:BoundField DataField="phone" HeaderText="phone" SortExpression="phone" /> <asp:BoundField DataField="address" HeaderText="address" SortExpression="address" /> <asp:BoundField DataField="city" HeaderText="city" SortExpression="city" /> <asp:BoundField DataField="state" HeaderText="state" SortExpression="state" /> <asp:BoundField DataField="zip" HeaderText="zip" SortExpression="zip" /> <asp:CheckBoxField DataField="contract" HeaderText="contract" SortExpression="contract" /> <asp:CommandField ShowEditButton="True" ShowInsertButton="True" /> </Fields> </asp:DetailsView>
<asp:SqlDataSource ID="SqlDataSource3" runat="server" ConnectionString="<%$ ConnectionStrings:Pubs %>" SelectCommand="SELECT [au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract] FROM [authors] WHERE ([au_id] = @au_id)" UpdateCommand="UPDATE [authors] SET [au_lname] = @au_lname, [au_fname] = @au_fname, [phone] = @phone, [address] = @address, [city] = @city, [state] = @state, [zip] = @zip, [contract] = @contract WHERE [au_id] = @au_id" InsertCommand="INSERT INTO [authors] ([au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract]) VALUES (@au_id, @au_lname, @au_fname, @phone, @address, @city, @state, @zip, @contract)"> <SelectParameters> <asp:ControlParameter ControlID="GridView1" Name="au_id" PropertyName="SelectedValue" Type="String" /> </SelectParameters> <UpdateParameters> <asp:Parameter Name="au_lname" Type="String" /> <asp:Parameter Name="au_fname" Type="String" /> <asp:Parameter Name="phone" Type="String" /> <asp:Parameter Name="address" Type="String" /> <asp:Parameter Name="city" Type="String" /> <asp:Parameter Name="state" Type="String" /> <asp:Parameter Name="zip" Type="String" /> <asp:Parameter Name="contract" Type="Boolean" /> <asp:Parameter Name="au_id" Type="String" /> </UpdateParameters> <InsertParameters> <asp:Parameter Name="au_id" Type="String" /> <asp:Parameter Name="au_lname" Type="String" /> <asp:Parameter Name="au_fname" Type="String" /> <asp:Parameter Name="phone" Type="String" /> <asp:Parameter Name="address" Type="String" /> <asp:Parameter Name="city" Type="String" /> <asp:Parameter Name="state" Type="String" /> <asp:Parameter Name="zip" Type="String" /> <asp:Parameter Name="contract" Type="Boolean" /> </InsertParameters> </asp:SqlDataSource> </td> </tr> </table> <br /> <asp:Label ID="ErrorMessageLabel" EnableViewState="false" runat="server" /> </form></body></html>
Web.config
<?xml version="1.0"?><configuration> <connectionStrings> <!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" /> --> <add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> <databases> <add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching> </system.web></configuration>
Podemos situar el DetailsView en una página separada para realizar las operaciones de Inserción o
Actualización. El siguiente ejemplo muestra un DetailsView configurado en una página separada para realizar
las Inserciones y Actualizaciones. Observar que la propiedad DefaultMode se ha fijado en el ejemplo a Insert o Edit, de forma que DetailsView se representará inicialmente en este modo, en lugar de el modo
sólo-lectura. Después de una Inserción o una Actualización, DetailsView siempre vuelve al DefaultMode (por defecto ReadOnly).
Inserción en Master-Details (Páginas Separadas)
GridViewMasterDetailsInsertPage_vb.aspx
<%@ Page Language="VB" %>
<script runat="server">
Protected Sub GridView1_RowDeleted(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewDeletedEventArgs) If (Not e.Exception Is Nothing) Then ErrorMessageLabel.Text = "Failed to DELETE due to foreign key contstraint on the table. You may only delete rows which have no related records." e.ExceptionHandled = True End If End Sub
</script>
<html><head runat="server"> <title>GridView DetailsView Master-Details (Edit and Insert Pages)</title></head><body> <form id="form1" runat="server"> <b>Choose a state:</b> <asp:DropDownList ID="DropDownList1" DataSourceID="SqlDataSource2" AutoPostBack="true" DataTextField="state" runat="server" /> <asp:SqlDataSource ID="SqlDataSource2" runat="server" SelectCommand="SELECT DISTINCT [state] FROM [authors]" ConnectionString="<%$ ConnectionStrings:Pubs %>" /> <br /> <br /> <asp:GridView ID="GridView1" AllowSorting="True" AllowPaging="True" runat="server" DataSourceID="SqlDataSource1" DataKeyNames="au_id" AutoGenerateColumns="False" Width="500px" OnRowDeleted="GridView1_RowDeleted"> <Columns> <asp:CommandField ShowDeleteButton="True" /> <asp:BoundField DataField="au_id" HeaderText="au_id" ReadOnly="True" SortExpression="au_id" /> <asp:BoundField DataField="au_lname" HeaderText="au_lname" SortExpression="au_lname" /> <asp:BoundField DataField="au_fname" HeaderText="au_fname" SortExpression="au_fname" /> <asp:BoundField DataField="state" HeaderText="state" SortExpression="state" /> <asp:HyperLinkField HeaderText="Edit..." Text="Edit..." DataNavigateUrlFields="au_id" DataNavigateUrlFormatString="DetailsViewEdit_vb.aspx?ID={0}" /> </Columns> </asp:GridView> <br /> <asp:HyperLink ID="HyperLink1" Text="Add New Author..." NavigateUrl="DetailsViewInsert_vb.aspx" 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)" DeleteCommand="DELETE FROM [authors] WHERE [au_id] = @au_id"> <SelectParameters> <asp:ControlParameter ControlID="DropDownList1" Name="state" PropertyName="SelectedValue" Type="String" /> </SelectParameters> <DeleteParameters> <asp:Parameter Name="au_id" Type="String" /> </DeleteParameters> </asp:SqlDataSource> <br /> <br />
<asp:Label ID="ErrorMessageLabel" EnableViewState="false" runat="server" /> </form></body></html>
DetailsViewEdit_vb.aspx
<%@ Page Language="VB" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><script runat="server">
Protected Sub DetailsView1_ItemUpdated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DetailsViewUpdatedEventArgs) Response.Redirect("GridViewMasterDetailsInsertPage_vb.aspx") End Sub Protected Sub DetailsView1_ModeChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DetailsViewModeEventArgs) If (e.CancelingEdit = True) Then Response.Redirect("GridViewMasterDetailsInsertPage_vb.aspx") End If End Sub</script><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server"> <title>DetailsView Edit</title></head><body> <form id="form1" runat="server"> <asp:DetailsView DefaultMode="Edit" AutoGenerateRows="False" DataKeyNames="au_id" DataSourceID="SqlDataSource3" HeaderText="Edit Author" ID="DetailsView1" runat="server" Width="275px" OnItemUpdated="DetailsView1_ItemUpdated" OnModeChanging="DetailsView1_ModeChanging"> <Fields> <asp:BoundField DataField="au_id" HeaderText="au_id" ReadOnly="True" SortExpression="au_id" /> <asp:BoundField DataField="au_lname" HeaderText="au_lname" SortExpression="au_lname" /> <asp:BoundField DataField="au_fname" HeaderText="au_fname" SortExpression="au_fname" /> <asp:BoundField DataField="phone" HeaderText="phone" SortExpression="phone" /> <asp:BoundField DataField="address" HeaderText="address" SortExpression="address" /> <asp:BoundField DataField="city" HeaderText="city" SortExpression="city" /> <asp:BoundField DataField="state" HeaderText="state" SortExpression="state" /> <asp:BoundField DataField="zip" HeaderText="zip" SortExpression="zip" /> <asp:CheckBoxField DataField="contract" HeaderText="contract" SortExpression="contract" /> <asp:CommandField ShowEditButton="True" /> </Fields>
</asp:DetailsView> <asp:SqlDataSource ID="SqlDataSource3" runat="server" ConnectionString="<%$ ConnectionStrings:Pubs %>" SelectCommand="SELECT [au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract] FROM [authors] WHERE ([au_id] = @au_id)" UpdateCommand="UPDATE [authors] SET [au_lname] = @au_lname, [au_fname] = @au_fname, [phone] = @phone, [address] = @address, [city] = @city, [state] = @state, [zip] = @zip, [contract] = @contract WHERE [au_id] = @au_id"> <SelectParameters> <asp:QueryStringParameter Name="au_id" QueryStringField="ID" Type="String" /> </SelectParameters> <UpdateParameters> <asp:Parameter Name="au_lname" Type="String" /> <asp:Parameter Name="au_fname" Type="String" /> <asp:Parameter Name="phone" Type="String" /> <asp:Parameter Name="address" Type="String" /> <asp:Parameter Name="city" Type="String" /> <asp:Parameter Name="state" Type="String" /> <asp:Parameter Name="zip" Type="String" /> <asp:Parameter Name="contract" Type="Boolean" /> <asp:Parameter Name="au_id" Type="String" /> </UpdateParameters> </asp:SqlDataSource> </form></body></html>
DetailsViewInsert_vb.aspx
<%@ Page Language="VB" %><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><script runat="server">
Protected Sub DetailsView1_ItemInserted(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DetailsViewInsertedEventArgs) Response.Redirect("GridViewMasterDetailsInsertPage_vb.aspx") End Sub Protected Sub DetailsView1_ModeChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DetailsViewModeEventArgs) If (e.CancelingEdit = True) Then Response.Redirect("GridViewMasterDetailsInsertPage_vb.aspx") End If End Sub</script><html xmlns="http://www.w3.org/1999/xhtml"><head runat="server"> <title>DetailsView Insert</title></head><body> <form id="form1" runat="server"> <asp:DetailsView DefaultMode="Insert" AutoGenerateRows="False" DataKeyNames="au_id"
DataSourceID="SqlDataSource3" HeaderText="Insert Author" ID="DetailsView1" runat="server" Width="275px" OnItemInserted="DetailsView1_ItemInserted" OnModeChanging="DetailsView1_ModeChanging"> <Fields> <asp:BoundField DataField="au_id" HeaderText="au_id" ReadOnly="True" SortExpression="au_id" /> <asp:BoundField DataField="au_lname" HeaderText="au_lname" SortExpression="au_lname" /> <asp:BoundField DataField="au_fname" HeaderText="au_fname" SortExpression="au_fname" /> <asp:BoundField DataField="phone" HeaderText="phone" SortExpression="phone" /> <asp:BoundField DataField="address" HeaderText="address" SortExpression="address" /> <asp:BoundField DataField="city" HeaderText="city" SortExpression="city" /> <asp:BoundField DataField="state" HeaderText="state" SortExpression="state" /> <asp:BoundField DataField="zip" HeaderText="zip" SortExpression="zip" /> <asp:CheckBoxField DataField="contract" HeaderText="contract" SortExpression="contract" /> <asp:CommandField ShowInsertButton="True" /> </Fields> </asp:DetailsView> <asp:SqlDataSource ID="SqlDataSource3" runat="server" ConnectionString="<%$ ConnectionStrings:Pubs %>" SelectCommand="SELECT [au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract] FROM [authors] WHERE ([au_id] = @au_id)" InsertCommand="INSERT INTO [authors] ([au_id], [au_lname], [au_fname], [phone], [address], [city], [state], [zip], [contract]) VALUES (@au_id, @au_lname, @au_fname, @phone, @address, @city, @state, @zip, @contract)"> <SelectParameters> <asp:QueryStringParameter Name="au_id" QueryStringField="ID" Type="String" /> </SelectParameters> <InsertParameters> <asp:Parameter Name="au_id" Type="String" /> <asp:Parameter Name="au_lname" Type="String" /> <asp:Parameter Name="au_fname" Type="String" /> <asp:Parameter Name="phone" Type="String" /> <asp:Parameter Name="address" Type="String" /> <asp:Parameter Name="city" Type="String" /> <asp:Parameter Name="state" Type="String" /> <asp:Parameter Name="zip" Type="String" /> <asp:Parameter Name="contract" Type="Boolean" /> </InsertParameters> </asp:SqlDataSource> </form></body></html>
Web.config
<?xml version="1.0"?><configuration> <connectionStrings>
<!-- This connection is inherited from the ASP.NET Quickstart Web.config file Uncomment this section to edit the sample locally
<add name="Pubs" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=pubs;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Northwind" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Northwind;Persist Security Info=True" providerName="System.Data.SqlClient" /> <add name="Contacts" connectionString="Server=(local)\SQLExpress;Integrated Security=True;Database=Contacts;Persist Security Info=True" providerName="System.Data.SqlClient" /> --> <add name="NorthwindOLEDB" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb;" providerName="System.Data.OleDb" /> <add name="ContactsDatabase" connectionString="Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Database.mdf;Integrated Security=True;User Instance=true;" providerName="System.Data.SqlClient" /> </connectionStrings> <system.web> <pages styleSheetTheme="Default"/> <caching> <sqlCacheDependency enabled="true" pollTime="1000"> <databases> <add name="Pubs" connectionStringName="Pubs"/> </databases> </sqlCacheDependency> </caching> </system.web></configuration>
Web.config