Usar consultas parametrizadas con SqlDataSource (VB)

por Scott Mitchell

Descargar PDF

En este tutorial, seguimos examinando el control SqlDataSource y aprendemos a definir consultas parametrizadas. Los parámetros se pueden especificar mediante declaración y mediante programación, y se pueden extraer de una serie de ubicaciones, como la cadena de consulta, el estado de sesión u otros controles.

Introducción

En el tutorial anterior vimos cómo usar el control SqlDataSource para recuperar datos directamente de una base de datos. Con el Asistente para configurar orígenes de datos, podríamos elegir la base de datos y, a continuación, elegir las columnas que se van a devolver de una tabla o vista, escribir una instrucción SQL personalizada o usar un procedimiento almacenado. Ya sea seleccionando columnas de una tabla o vista o escribiendo una instrucción SQL personalizada, a la propiedad SelectCommand del control SqlDataSource se le asigna la instrucción SQL ad-hoc SELECT resultante y es esta instrucción SELECT la que se ejecuta cuando se invoca el método Select() de SqlDataSource (ya sea mediante programación o automáticamente desde un control web de datos).

Las instrucciones SQL SELECT usadas en las demostraciones del tutorial anterior carecen de cláusulas WHERE. En una instrucción SELECT, la cláusula WHERE se puede usar para limitar los resultados devueltos. Por ejemplo, para mostrar los nombres de los productos que cuestan más de 50,00 USD, podríamos usar la consulta siguiente:

SELECT ProductName
FROM Products
WHERE UnitPrice > 50.00

Normalmente, algunos orígenes externos determinan los valores usados en una cláusula WHERE, como un valor de cadena de consulta, una variable de sesión o una entrada de usuario de un control web en la página. Idealmente, estas entradas se especifican mediante el uso de parámetros. Con Microsoft SQL Server, los parámetros se indican mediante @parameterName, como en:

SELECT ProductName
FROM Products
WHERE UnitPrice > @Price

SqlDataSource admite consultas parametrizadas, tanto para instrucciones SELECT como para instrucciones INSERT, UPDATEy DELETE. Además, los valores de parámetro se pueden extraer automáticamente de una variedad de orígenes la cadena de consulta, el estado de sesión, los controles de la página, etc. o se pueden asignar mediante programación. En este tutorial, veremos cómo definir consultas parametrizadas, así como cómo especificar los valores de parámetro tanto mediante declaración como mediante programación.

Nota:

En el tutorial anterior comparamos ObjectDataSource, que ha sido nuestra herramienta preferida en los primeros 46 tutoriales, con SqlDataSource, teniendo en cuenta sus similitudes conceptuales. Estas similitudes también se extienden a los parámetros. Los parámetros ObjectDataSource se asignaron a los parámetros de entrada de los métodos de la capa de lógica empresarial. Con SqlDataSource, los parámetros se definen directamente dentro de la consulta SQL. Ambos controles tienen colecciones de parámetros para sus métodos Select(), Insert(), Update() y Delete(), y ambos pueden tener estos valores de parámetros rellenados desde fuentes predefinidas (valores de cadena de consulta, variables de sesión, etc.) o asignados mediante programación.

Crear una consulta parametrizada

El Asistente para configurar orígenes de datos del control SqlDataSource ofrece tres vías para definir el comando que se va a ejecutar para recuperar registros de base de datos:

  • seleccionar las columnas de una tabla o vista existente,
  • escribir una instrucción SQL personalizada, o
  • elegir un procedimiento almacenado.

Al seleccionar columnas de una tabla o vista existente, los parámetros de la cláusula WHERE deben especificarse mediante el cuadro de diálogo Agregar cláusula WHERE. Sin embargo, al crear una instrucción SQL personalizada, puede escribir los parámetros directamente en la cláusula WHERE (usando @parameterName para indicar cada parámetro). Un procedimiento almacenado consta de una o varias instrucciones SQL y estas instrucciones se pueden parametrizar. Los parámetros usados en las instrucciones SQL, sin embargo, deben pasarse como parámetros de entrada al procedimiento almacenado.

Dado que la creación de una consulta parametrizada depende de cómo se especifican los elementos SqlDataSource SelectCommand, echemos un vistazo a los tres enfoques. Para empezar, abra la página ParameterizedQueries.aspx en la carpeta SqlDataSource, arrastre un control SqlDataSource desde el Cuadro de herramientas al Diseñador y establezca su ID en Products25BucksAndUnderDataSource. A continuación, haga clic en el vínculo Configurar origen de datos desde la etiqueta inteligente del control. Seleccione la base de datos para usar (NORTHWINDConnectionString) y haga clic en Siguiente.

Paso 1: Agregar una cláusula WHERE al seleccionar las columnas de una tabla o vista

Al seleccionar los datos que se van a devolver de la base de datos con el control SqlDataSource, el Asistente para configurar orígenes de datos nos permite elegir simplemente las columnas que se van a devolver de una tabla o vista existente (vea la figura 1). Al hacerlo, se compila automáticamente una instrucción SELECT SQL, que es lo que se envía a la base de datos cuando se invoca el método Select() de SqlDataSource. Como hicimos en el tutorial anterior, seleccione la tabla Products en la lista desplegable y compruebe las columnas ProductID, ProductName y UnitPrice.

Pick the Columns to Return from a Table or View

Figura 1: Selección de las columnas que se van a devolver de una tabla o vista (haga clic para ver la imagen a tamaño completo)

Para incluir una cláusula WHERE en la instrucción SELECT, haga clic en el botón WHERE, que abre el cuadro de diálogo Agregar cláusula WHERE (vea la figura 2). Para agregar un parámetro para limitar los resultados devueltos por la consulta SELECT, primero elija la columna por la que filtrar los datos. A continuación, elija el operador que se va a usar para filtrar (=, <, <=, >, etc.). Por último, elija el origen del valor del parámetro, como desde la cadena de consulta o el estado de sesión. Después de configurar el parámetro, haga clic en el botón Agregar para incluirlo en la consulta SELECT.

En este ejemplo, vamos a devolver solo los resultados en los que el valor UnitPrice sea menor o igual que 25,00 USD. Por lo tanto, elija UnitPrice de la lista desplegable Columna y <= de la lista desplegable Operador. Al usar un valor de parámetro codificado de forma rígida (por ejemplo, 25,00 USD) o si el valor del parámetro se va a especificar mediante programación, seleccione Ninguno en la lista desplegable Origen. A continuación, escriba el valor del parámetro codificado de forma rígida en el cuadro de texto Valor 25.00 y complete el proceso haciendo clic en el botón Agregar.

Limit the Results Returned from the Add WHERE Clause Dialog Box

Figura 2: Limitar los resultados devueltos desde el cuadro de diálogo Agregar cláusula WHERE (haga clic para ver la imagen a tamaño completo)

Después de agregar el parámetro, haga clic en Aceptar para volver al Asistente para configurar orígenes de datos. La instrucción SELECT de la parte inferior del Asistente ahora debe incluir una cláusula WHERE con un parámetro denominado @UnitPrice:

SELECT [ProductID], [ProductName], [UnitPrice]
FROM [Products]
WHERE ([UnitPrice] <= @UnitPrice)

Nota:

Si especifica varias condiciones en la cláusula WHERE del cuadro de diálogo Agregar cláusula WHERE, el asistente las une con el operador AND. Si necesita incluir un elemento OR en la cláusula WHERE (por ejemplo, WHERE UnitPrice <= @UnitPrice OR Discontinued = 1), tendrá que compilar la instrucción SELECT a través de la pantalla de instrucciones SQL personalizada.

Complete la configuración de SqlDataSource (haga clic en Siguiente y, a continuación, en Finalizar) y, a continuación, inspeccione el marcado declarativo de SqlDataSource. El marcado ahora incluye una colección <SelectParameters>, que escribe los orígenes de los parámetros en SelectCommand.

<asp:SqlDataSource ID="Products25BucksAndUnderDataSource" runat="server"
    ConnectionString="<%$ ConnectionStrings:NORTHWNDConnectionString %>"
    SelectCommand=
        "SELECT [ProductID], [ProductName], [UnitPrice]
        FROM [Products] WHERE ([UnitPrice] <= @UnitPrice)">
    <SelectParameters>
        <asp:Parameter DefaultValue="25.00" Name="UnitPrice" Type="Decimal" />
    </SelectParameters>
</asp:SqlDataSource>

Cuando se invoca el método Select() de SqlDataSource, el valor UnitPrice del parámetro (25,00) se aplica al parámetro @UnitPrice en SelectCommand antes de enviarse a la base de datos. El resultado neto es que solo se devuelven de la tabla Products los productos con un precio menor o igual a 25,00 USD. Para confirmarlo, agregue una clase GridView a la página, vincúlela a este origen de datos y, a continuación, vea la página a través de un explorador. Solo debería ver los productos enumerados con precios menores o iguales a 25,00 USD, como confirma la figura 3.

Only Those Products Less Than or Equal to $25.00 are Displayed

Figura 3: Solo se muestran los productos con precios menores o iguales a 25,00 USD (haga clic para ver la imagen a tamaño completo)

Paso 2: Agregar parámetros a una instrucción SQL personalizada

Al agregar una instrucción SQL personalizada, puede especificar explícitamente la cláusula WHERE o especificar un valor en la celda Filtro del Generador de consultas. Para demostrar esto, vamos a mostrar solo aquellos productos en un GridView cuyos precios sean inferiores a un determinado umbral. Empiece agregando un cuadro de texto a la página ParameterizedQueries.aspx para recopilar este valor de umbral del usuario. Establezca la propiedad ID de TextBox en MaxPrice. Agregue un control web de botón y establezca su propiedad Text en Mostrar productos coincidentes.

A continuación, arrastre un objeto GridView a la página y desde su etiqueta inteligente elija crear un nuevo SqlDataSource llamado ProductsFilteredByPriceDataSource. En el Asistente para configurar orígenes de datos, vaya a la pantalla Especificar una instrucción SQL personalizada o un procedimiento almacenado (vea la figura 4) y escriba la consulta siguiente:

SELECT ProductName, UnitPrice
FROM Products
WHERE UnitPrice <= @MaximumPrice OR @MaximumPrice = -1.0

Después de escribir la consulta (manualmente o a través del Generador de consultas), haga clic en Siguiente.

Return Only Those Products Less Than or Equal to a Parameter Value

Figura  4: Devolver solo los productos con precios inferiores o iguales a un valor de parámetro (haga clic para ver la imagen a tamaño completo)

Dado que la consulta incluye parámetros, la siguiente pantalla del Asistente nos pide el origen de los valores de parámetros. Elija Control en la lista desplegable Origen de parámetros y MaxPrice (el valor del ID control del cuadro de texto) en la lista desplegable ControlID. También puede escribir un valor predeterminado opcional que se usará en el caso de que el usuario no haya escrito ningún texto en el cuadro de texto MaxPrice. Por el momento, no escriba un valor predeterminado.

The MaxPrice TextBox s Text Property is Used as the Parameter Source

Figura 5: La propiedad Text del cuadro de texto MaxPrice se usa como origen de parámetros (haga clic para ver la imagen a tamaño completo)

Complete el Asistente para configurar orígenes de datos; para ello, haga clic en Siguiente y, a continuación, en Finalizar. A continuación se muestra el marcado declarativo para GridView, TextBox, Button y SqlDataSource:

Maximum price:
$<asp:TextBox ID="MaxPrice" runat="server" Columns="5" />
 
<asp:Button ID="DisplayProductsLessThanButton" runat="server"
    Text="Display Matching Products" />
<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False"
    DataSourceID="ProductsFilteredByPriceDataSource" EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="ProductName" HeaderText="Product"
            SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" HeaderText="Price"
            HtmlEncode="False" DataFormatString="{0:c}"
            SortExpression="UnitPrice" />
    </Columns>
</asp:GridView>
<asp:SqlDataSource ID="ProductsFilteredByPriceDataSource" runat="server"
    ConnectionString="<%$ ConnectionStrings:NORTHWNDConnectionString %>"
    SelectCommand=
        "SELECT ProductName, UnitPrice 
        FROM Products WHERE UnitPrice <= @MaximumPrice">
    <SelectParameters>
        <asp:ControlParameter ControlID="MaxPrice" Name="MaximumPrice"
            PropertyName="Text" />
    </SelectParameters>
</asp:SqlDataSource>

Tenga en cuenta que el parámetro de la sección <SelectParameters> de SqlDataSource es un ControlParameter, que incluye propiedades adicionales como ControlID y PropertyName. Cuando se invoca el método Select() de SqlDataSource, ControlParameter toma el valor de la propiedad de control web especificada y lo asigna al parámetro correspondiente en SelectCommand. En este ejemplo, la propiedad de texto MaxPrice se usa como valor de parámetro @MaxPrice.

Dedique un minuto a ver esta página a través de un explorador. Cuando se visita la página por primera vez o cuando el cuadro te xto MaxPrice carece de un valor no se muestran registros en el objeto GridView.

No Records are Displayed When the MaxPrice TextBox is Empty

Figura 6: No se muestran registros cuando el cuadro de texto MaxPrice está vacío (haga clic para ver la imagen a tamaño completo)

La razón por la que no se muestran productos es porque, de manera predeterminada, una cadena vacía para un valor de parámetro se convierte en un valor de base de datos NULL. Puesto que la comparación de [UnitPrice] <= NULL siempre se evalúa como falsa, no se devuelve ningún resultado.

Escriba un valor en el cuadro de texto, como 5.00, y haga clic en el botón Mostrar productos coincidentes. En postback, SqlDataSource informa a GridView de que uno de sus orígenes de parámetros ha cambiado. Por lo tanto, GridView se vuelve a enlazar a SqlDataSource, mostrando esos productos con precios menores o iguales que 5,00 USD.

Products Less Than or Equal to $5.00 are Displayed

Figura 7: Se muestran los productos con precios menores o iguales a 5,00 USD (haga clic para ver la imagen a tamaño completo)

Muestra inicial de todos los productos

En lugar de no mostrar ningún producto cuando la página se carga por primera vez, es posible que deseemos mostrar todos los productos. Una forma de enumerar todos los productos cuando el cuadro de texto MaxPrice está vacío es establecer el valor predeterminado del parámetro en un valor increíblemente alto, como 1000000, ya que es poco probable que Northwind Traders tenga alguna vez un inventario cuyo precio unitario supere la cantidad de 1.000.000 USD. Sin embargo, este enfoque es corto de miras y podría no funcionar en otras situaciones.

En tutoriales anteriores: Parámetros declarativos y Filtrado de maestro y detalles con una lista desplegable, nos hemos enfrentado a un problema similar. Nuestra solución fue poner esta lógica en la capa de lógica empresarial. En concreto, BLL examinó el valor entrante y, si era NULL o algún valor reservado, la llamada se enrutaba al método DAL que devolvía todos los registros. Si el valor entrante era un valor de filtrado normal, se realizaba una llamada al método DAL que ejecutaba una instrucción SQL que utilizaba una cláusula WHERE parametrizada con el valor suministrado.

Desafortunadamente, se omite la arquitectura al usar SqlDataSource. En su lugar, es necesario personalizar la instrucción SQL para capturar de forma inteligente todos los registros si el parámetro @MaximumPrice es NULL o algún valor reservado. Para este ejercicio, hagámoslo de manera que si el parámetro @MaximumPrice es igual a -1.0, entonces todos los registros deben devolverse (-1.0 funciona como un valor reservado, ya que ningún producto puede tener un valor UnitPrice negativo). Para ello, podemos usar la siguiente instrucción SQL:

SELECT ProductName, UnitPrice
FROM Products
WHERE UnitPrice <= @MaximumPrice OR @MaximumPrice = -1.0

Esta cláusula WHERE devuelve todos los registros si el parámetro @MaximumPrice es igual a -1.0. Si el valor del parámetro no es -1.0, solo se devuelven los productos cuyo valor UnitPrice sea menor o igual que el valor del parámetro @MaximumPrice. Al establecer el valor predeterminado del parámetro @MaximumPrice en -1.0, en la primera carga de página (o siempre que el cuadro de texto MaxPrice esté vacío), @MaximumPrice tendrá un valor de -1.0 y se mostrarán todos los productos.

Now All Products are Displayed When the MaxPrice TextBox is Empty

Figura 8: Ahora se muestran todos los productos cuando el cuadro de texto MaxPrice está vacío (haga clic para ver la imagen a tamaño completo)

Hay un par de advertencias que se deben tener en cuenta con este enfoque. En primer lugar, tenga en cuenta que el tipo de datos del parámetro se deduce por su uso en la consulta SQL. Si cambia la cláusula WHERE de @MaximumPrice = -1.0 a @MaximumPrice = -1, el entorno de ejecución trata el parámetro como un entero. Si luego intenta asignar el cuadro de texto MaxPrice a un valor decimal (como 5,00 ), se producirá un error porque no puede convertir 5,00 a un entero. Para solucionar este problema, asegúrese de usar @MaximumPrice = -1.0 en la cláusula WHERE o, mejor aún, establezca la propiedad Type del objeto ControlParameter en Decimal.

En segundo lugar, al agregar el elemento OR @MaximumPrice = -1.0 a la cláusula WHERE, el motor de consultas no puede usar un índice en UnitPrice (suponiendo que exista uno), lo que da lugar a un recorrido de tabla. Esto puede afectar al rendimiento si hay un número suficientemente grande de registros en la tabla Products. Un mejor enfoque sería mover esta lógica a un procedimiento almacenado en el que una instrucción IF realizaría una consulta SELECT desde la tabla Products sin una cláusula WHERE cuando se deban devolver todos los registros, o uno cuya cláusula WHERE contenga solo los criterios UnitPrice, de modo que se pueda usar un índice.

Paso 3: Crear y usar procedimientos almacenados con parámetros

Los procedimientos almacenados pueden incluir un conjunto de parámetros de entrada que se pueden usar en las instrucciones SQL definidas en el procedimiento almacenado. Al configurar SqlDataSource para usar un procedimiento almacenado que acepta parámetros de entrada, estos valores de parámetro se pueden especificar mediante las mismas técnicas que con instrucciones SQL ad hoc.

Para ilustrar el uso de procedimientos almacenados en SqlDataSource, vamos a crear un nuevo procedimiento almacenado en la base de datos Northwind denominado GetProductsByCategory, que acepta un parámetro denominado @CategoryID y devuelve todas las columnas de los productos cuya columna CategoryID coincida con @CategoryID. Para crear un procedimiento almacenado, vaya al Explorador de servidores y explore en profundidad la base de datos NORTHWND.MDF. (Si no ve el Explorador de servidores, hágalo aparecer yendo al menú Ver y seleccionando la opción Explorador de servidores).

En la base de datos NORTHWND.MDF, haga clic con el botón derecho en la carpeta Procedimientos almacenados, seleccione Agregar nuevo procedimiento almacenado y escriba la siguiente sintaxis:

CREATE PROCEDURE dbo.GetProductsByCategory
(
      @CategoryID int
)
AS
SELECT *
FROM Products
WHERE CategoryID = @CategoryID

Haga clic en el icono Guardar (o Ctrl+S) para guardar el procedimiento almacenado. Para probar el procedimiento almacenado, haga clic con el botón derecho en él en la carpeta Procedimientos almacenados y elija Ejecutar. Esto le pedirá los parámetros del procedimiento almacenado (@CategoryID, en esta instancia), después de lo cual los resultados se mostrarán en la ventana Salida.

The GetProductsByCategory Stored Procedure when Executed with a <span class=@CategoryID of 1" />

Figura 9: Procedimiento almacenado GetProductsByCategory cuando se ejecuta con un @CategoryID de 1 (haga clic para ver la imagen a tamaño completo)

Vamos a usar este procedimiento almacenado para mostrar todos los productos de la categoría Bebidas en una clase GridView. Agregue una nueva clase GridView a la página y enlácelo a un nuevo objeto SqlDataSource denominado BeverageProductsDataSource. Continúe con la pantalla Especificar una instrucción SQL personalizada o un procedimiento almacenado, seleccione el botón de radio Procedimiento almacenado y elija el procedimiento almacenado GetProductsByCategory en la lista desplegable.

Select the GetProductsByCategory Stored Procedure from the Drop-Down List

Figura 10: Seleccionar el procedimiento almacenado GetProductsByCategory en la lista desplegable (haga clic para ver la imagen a tamaño completo)

Dado que el procedimiento almacenado acepta un parámetro de entrada (@CategoryID), al hacer clic en Siguiente se nos pide que especifiquemos el origen para este valor de parámetro. El valor CategoryID de las bebidas es 1, por lo que deje la lista desplegable Origen de parámetros en Ninguno y escriba 1 en el cuadro de texto DefaultValue.

Use a Hard-Coded Value of 1 to Return the Products in the Beverages Category

Figura 11: Usar un valor codificado de forma rígida de 1 para devolver los productos en la categoría bebidas (haga clic para ver la imagen a tamaño completo)

Como muestra el siguiente marcado declarativo, cuando se utiliza un procedimiento almacenado, la propiedad SelectCommand de SqlDataSource se establece en el nombre del procedimiento almacenado y la propiedad SelectCommandType se establece en StoredProcedure, indicando que SelectCommand es el nombre de un procedimiento almacenado en lugar de una instrucción SQL ad-hoc.

<asp:SqlDataSource ID="BeverageProductsDataSource" runat="server"
    ConnectionString="<%$ ConnectionStrings:NORTHWNDConnectionString %>"
    SelectCommand="GetProductsByCategory" SelectCommandType="StoredProcedure">
    <SelectParameters>
        <asp:Parameter DefaultValue="1" Name="CategoryID" Type="Int32" />
    </SelectParameters>
</asp:SqlDataSource>

Pruebe la página en un explorador. Solo se muestran los productos que pertenecen a la categoría Bebidas, aunque se muestran todos los campos del producto, ya que el procedimiento almacenado GetProductsByCategory devuelve todas las columnas de la tabla Products. Por supuesto, podríamos limitar o personalizar los campos mostrados en GridView desde el cuadro de diálogo Editar columnas de GridView.

All of the Beverages are Displayed

Figura 12: Se muestran todas las bebidas (haga clic para ver la imagen a tamaño completo)

Paso 4: Invocar mediante programación una instrucción Select() de SqlDataSource

Los ejemplos que hemos visto en el tutorial anterior y este tutorial hasta ahora han enlazado controles SqlDataSource directamente a GridView. Sin embargo, se puede acceder a los datos del control SqlDataSource mediante programación y luego enumerarlos en el código. Esto puede ser especialmente útil cuando necesita consultar datos para inspeccionarlos, pero no es necesario mostrarlos. En lugar de tener que escribir todo el código ADO.NET para conectarse a la base de datos, especificar el comando y recuperar los resultados, puede dejar que SqlDataSource se encargue de este monótono código.

Para ilustrar el trabajo con los datos de SqlDataSource mediante programación, imagine que su jefe le ha pedido que cree una página web que muestre el nombre de una categoría seleccionada al azar y sus productos asociados. Es decir, cuando un usuario visita esta página, queremos elegir aleatoriamente una categoría de la tabla Categories, mostrar el nombre de categoría y, a continuación, enumerar los productos que pertenecen a esa categoría.

Para ello necesitamos dos controles SqlDataSource: uno para obtener una categoría aleatoria de la tabla Categories y otro para obtener los productos de la categoría. En este paso crearemos el SqlDataSource que recupera un registro aleatorio de la categoría; en el paso 5 veremos cómo crear el SqlDataSource que recupera los productos de la categoría.

Empiece agregando un objeto SqlDataSource a ParameterizedQueries.aspx y establezca su ID en RandomCategoryDataSource. Configúrelo para que use la siguiente consulta SQL:

SELECT TOP 1 CategoryID, CategoryName
FROM Categories
ORDER BY NEWID()

ORDER BY NEWID() devuelve los registros ordenados en orden aleatorio (vea Uso de NEWID() para ordenar registros aleatoriamente). SELECT TOP 1 devuelve el primer registro del conjunto de resultados. En conjunto, esta consulta devuelve los valores de las columnas CategoryID y CategoryName de una única categoría seleccionada aleatoriamente.

Para mostrar el valor CategoryName de la categoría, agregue un control de etiqueta web a la página, establezca su propiedad ID en CategoryNameLabel y elimine su propiedad Text. Para recuperar mediante programación los datos de un control SqlDataSource, es necesario invocar su método Select(). El método Select() espera un único parámetro de entrada de tipo DataSourceSelectArguments, que especifica cómo se deben enviar mensajes a los datos antes de devolverse. Esto puede incluir instrucciones sobre la ordenación y el filtrado de los datos, y los controles web de datos lo usan al ordenar o paginar a través de los datos de un control SqlDataSource. Sin embargo, en nuestro ejemplo no es necesario modificar los datos antes de devolverlos, y por lo tanto pasaremos el objeto DataSourceSelectArguments.Empty.

El método Select() devuelve un objeto que implementa IEnumerable. El tipo preciso devuelto depende del valor de la propiedad DataSourceMode del control SqlDataSource. Como se explicó en el tutorial anterior, esta propiedad se puede establecer en un valor de DataSet o DataReader. Si se establece en DataSet, el método Select() devuelve un objeto DataView; si se establece en DataReader, devuelve un objeto que implementa IDataReader. Dado que el RandomCategoryDataSource SqlDataSource tiene su DataSourceMode propiedad establecida en DataSet (valor predeterminado), trabajaremos con un objeto DataView.

En el código siguiente se muestra cómo recuperar los registros de RandomCategoryDataSource SqlDataSource como dataView, así como cómo leer el valor de columna CategoryName de la primera fila DataView:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles Me.Load
    ' Get the data from the SqlDataSource as a DataView
    Dim randomCategoryView As DataView = CType _
        (RandomCategoryDataSource.Select(DataSourceSelectArguments.Empty), DataView)
    If randomCategoryView.Count > 0 Then
        ' Assign the CategoryName value to the Label
        CategoryNameLabel.Text = String.Format( _
            "Here are Products in the {0} Category...", _
            randomCategoryView(0)("CategoryName").ToString())
    End If
End Sub

randomCategoryView(0) devuelve el primer DataRowView en DataView. randomCategoryView(0)("CategoryName") devuelve el valor de la columna CategoryName en esta primera fila. Tenga en cuenta que dataView está escrito de forma flexible. Para hacer referencia a un valor de columna determinado, es necesario pasar el nombre de la columna como una cadena ( CategoryName, en este caso). En la figura 13 se muestra el mensaje mostrado en CategoryNameLabel al ver la página. Por supuesto, el nombre de categoría real que se muestra está seleccionado aleatoriamente por el RandomCategoryDataSource SqlDataSource en cada visita a la página (incluidos los postbacks).

The Randomly Selected Category s Name is Displayed

Figura 13: Se muestra el nombre de la categoría seleccionada aleatoriamente (haga clic para ver la imagen a tamaño completo)

Nota:

Si la propiedad DataSourceMode del control SqlDataSource se hubiera establecido en DataReader, el valor devuelto del método Select() tendría que convertirse en IDataReader. Para leer el valor de columna CategoryName de la primera fila, usaríamos código como:

If randomCategoryReader.Read() Then
   Dim categoryName as String = randomCategoryReader("CategoryName').ToString()
   ...
End If

Con el SqlDataSource seleccionando aleatoriamente una categoría, estamos listos para agregar el GridView que enumera los productos de la categoría.

Nota:

En lugar de usar un control de etiqueta web para mostrar el nombre de la categoría, podríamos haber agregado un FormView o DetailsView a la página, enlazándolo a SqlDataSource. Sin embargo, el uso de la etiqueta nos permitió explorar cómo invocar mediante programación la instrucción Select() de SqlDataSource y trabajar con sus datos resultantes en el código.

Paso 5: Asignar valores de parámetro mediante programación

Todos los ejemplos que hemos visto hasta ahora en este tutorial han usado un valor de parámetro codificado de forma rígida o uno tomado de uno de los orígenes de parámetros predefinidos (un valor de cadena de consulta, un control web en la página, etc.). Sin embargo, los parámetros del control SqlDataSource también se pueden establecer mediante programación. Para completar nuestro ejemplo actual, necesitamos un objeto SqlDataSource que devuelva todos los productos que pertenecen a una categoría especificada. Este objeto SqlDataSource tendrá un parámetro CategoryID cuyo valor debe establecerse en función del valor de columna CategoryID devuelto por el RandomCategoryDataSource SqlDataSource en el controlador de eventos Page_Load.

Empiece por agregar una nueva clase GridView a la página y enlácela a un nuevo objeto SqlDataSource denominado ProductsByCategoryDataSource. Al igual que hicimos en el paso 3, configure SqlDataSource para que invoque el procedimiento almacenado GetProductsByCategory. Deje la lista desplegable Origen de parámetros establecida en Ninguno, pero no escriba un valor predeterminado, ya que estableceremos este valor predeterminado mediante programación.

Screenshot showing the Configure Data Source window with the Parameter source set to None.

Figura 14: No especificar un origen de parámetro o un valor predeterminado (haga clic para ver la imagen a tamaño completo)

Después de completar el Asistente de SqlDataSource, el marcado declarativo resultante debe ser similar al siguiente:

<asp:SqlDataSource ID="ProductsByCategoryDataSource" runat="server"
    ConnectionString="<%$ ConnectionStrings:NORTHWNDConnectionString %>"
    SelectCommand="GetProductsByCategory" SelectCommandType="StoredProcedure">
    <SelectParameters>
        <asp:Parameter Name="CategoryID" Type="Int32" />
    </SelectParameters>
</asp:SqlDataSource>

Podemos asignar el DefaultValue del parámetro CategoryID mediante programación en el controlador de eventos Page_Load:

' Assign the ProductsByCategoryDataSource's
' CategoryID parameter's DefaultValue property
ProductsByCategoryDataSource.SelectParameters("CategoryID").DefaultValue = _
    randomCategoryView(0)("CategoryID").ToString()

Con esta adición, la página incluye una clase GridView que muestra los productos asociados a la categoría seleccionada aleatoriamente.

Screenshot showing the Your Randomly Selected Category page.

Figura 15: No especificar un origen de parámetro o un valor predeterminado (haga clic para ver la imagen a tamaño completo)

Resumen

SqlDataSource permite a los desarrolladores de páginas definir consultas parametrizadas cuyos valores de parámetro se pueden codificar de forma rígida, extraerse de orígenes de parámetros predefinidos o asignarse mediante programación. En este tutorial hemos visto cómo crear una consulta parametrizada desde el Asistente para configurar orígenes de datos para consultas SQL ad hoc y procedimientos almacenados. También hemos examinado el uso de orígenes de parámetros codificados de forma rígida, un control web como origen de parámetros y la especificación mediante programación del valor del parámetro.

Al igual que con ObjectDataSource, SqlDataSource también proporciona funcionalidades para modificar sus datos subyacentes. En el siguiente tutorial veremos cómo definir instrucciones INSERT, UPDATE y DELETE con SqlDataSource. Una vez agregadas estas instrucciones, podemos usar las características integradas de inserción, edición y eliminación inherentes a los controles GridView, DetailsView y FormView.

¡Feliz programación!

Acerca del autor

Scott Mitchell, autor de siete libros de ASP/ASP.NET y fundador de 4GuysFromRolla.com, ha estado trabajando con tecnologías web de Microsoft desde 1998. Scott trabaja como consultor independiente, entrenador y escritor. Su último libro es Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Puede ponerse en contacto con él via mitchell@4GuysFromRolla.com. o a través de su blog, que se puede encontrar en http://ScottOnWriting.NET.

Agradecimientos especiales a

Esta serie de tutoriales fue revisada por muchos revisores de gran ayuda. Los revisores principales de este tutorial fueron Scott Clyde, Randell Schmidt y Ken Pespisa. ¿Le interesa revisar mis próximos artículos de MSDN? Si es así, escríbame a mitchell@4GuysFromRolla.com.