Uso de consultas parametrizadas com o SqlDataSource (C#)

por Scott Mitchell

Baixar PDF

Neste tutorial, continuamos nossa análise do controle SqlDataSource e aprendemos a definir consultas parametrizadas. Os parâmetros podem ser especificados de forma declarativa e programática e podem ser extraídos de vários locais, como a querystring, o estado de sessão, outros controles e muito mais.

Introdução

No tutorial anterior, vimos como usar o controle SqlDataSource para recuperar dados diretamente de um banco de dados. Usando o assistente Configurar Fonte de Dados, podemos escolher o banco de dados e, em seguida, escolher as colunas para retornar de uma tabela ou exibição; insira uma instrução SQL personalizada; ou use um procedimento armazenado. Seja selecionando colunas de uma tabela ou exibição ou inserindo uma instrução SQL personalizada, a propriedade do SelectCommand controle SqlDataSource recebe a instrução SQL SELECT ad hoc resultante e é essa SELECT instrução executada quando o método sqlDataSource Select() é invocado (programaticamente ou automaticamente de um controle da Web de dados).

As instruções SQL SELECT usadas nas demonstrações do tutorial anterior não tinham WHERE cláusulas. Em uma SELECT instrução , a WHERE cláusula pode ser usada para limitar os resultados retornados. Por exemplo, para exibir os nomes de produtos que custam mais de US$ 50,00, poderíamos usar a seguinte consulta:

SELECT ProductName
FROM Products
WHERE UnitPrice > 50.00

Normalmente, os valores usados em uma WHERE cláusula são determinados por alguma fonte externa, como um valor de querystring, uma variável de sessão ou entrada de usuário de um controle web na página. O ideal é que essas entradas sejam especificadas por meio do uso de parâmetros. Com o Microsoft SQL Server, os parâmetros são indicados usando @parameterName, como em:

SELECT ProductName
FROM Products
WHERE UnitPrice > @Price

O SqlDataSource dá suporte a consultas parametrizadas, tanto para instruções quanto INSERTpara SELECT instruções , UPDATEe DELETE . Além disso, os valores de parâmetro podem ser extraídos automaticamente de uma variedade de fontes que a querystring, o estado da sessão, os controles na página e assim por diante ou podem ser atribuídos programaticamente. Neste tutorial, veremos como definir consultas parametrizadas, bem como especificar os valores de parâmetro declarativamente e programaticamente.

Observação

No tutorial anterior, comparamos o ObjectDataSource, que foi nossa ferramenta de escolha nos primeiros 46 tutoriais com o SqlDataSource, observando suas semelhanças conceituais. Essas semelhanças também se estendem aos parâmetros. Os parâmetros objectDataSource mapeados para os parâmetros de entrada para os métodos na Camada lógica de negócios. Com o SqlDataSource, os parâmetros são definidos diretamente na consulta SQL. Ambos os controles têm coleções de parâmetros para seus Select()métodos , Insert(), Update()e Delete() e ambos podem ter esses valores de parâmetro preenchidos de fontes predefinidas (valores de querystring, variáveis de sessão e assim por diante) ou atribuídos programaticamente.

Criando uma consulta parametrizada

O assistente Configurar Fonte de Dados do sqlDataSource oferece três caminhos para definir o comando a ser executado para recuperar registros de banco de dados:

  • Escolhendo as colunas de uma tabela ou exibição existente,
  • Inserindo uma instrução SQL personalizada ou
  • Escolhendo um procedimento armazenado

Ao escolher colunas de uma tabela ou exibição existente, os parâmetros da WHERE cláusula devem ser especificados por meio da caixa de diálogo Adicionar WHERE Cláusula. No entanto, ao criar uma instrução SQL personalizada, você pode inserir os parâmetros diretamente na WHERE cláusula (usando @parameterName para denotar cada parâmetro). Um procedimento armazenado consiste em uma ou mais instruções SQL e essas instruções podem ser parametrizadas. Os parâmetros usados nas instruções SQL, no entanto, devem ser passados como parâmetros de entrada para o procedimento armazenado.

Como a criação de uma consulta parametrizada depende de como o SqlDataSource s SelectCommand é especificado, vamos dar uma olhada nas três abordagens. Para começar, abra a ParameterizedQueries.aspx página na SqlDataSource pasta , arraste um controle SqlDataSource da Caixa de Ferramentas para o Designer e defina como IDProducts25BucksAndUnderDataSource. Em seguida, clique no link Configurar Fonte de Dados da marca inteligente do controle. Selecione o banco de dados a ser usado (NORTHWINDConnectionString) e clique em Avançar.

Etapa 1: Adicionar uma cláusula WHERE ao escolher as colunas de uma tabela ou exibição

Ao selecionar os dados a serem retornados do banco de dados com o controle SqlDataSource, o assistente Configurar Fonte de Dados nos permite simplesmente escolher as colunas a serem retornadas de uma tabela ou exibição existente (consulte a Figura 1). Isso cria automaticamente uma instrução SQL SELECT , que é o que é enviado ao banco de dados quando o método sqlDataSource Select() é invocado. Como fizemos no tutorial anterior, selecione a tabela Produtos na lista suspensa e marcar as ProductIDcolunas , ProductNamee UnitPrice .

Escolher as colunas a serem retornadas de uma tabela ou exibição

Figura 1: escolha as colunas a serem retornadas de uma tabela ou exibição (clique para exibir a imagem em tamanho real)

Para incluir uma WHERE cláusula na SELECT instrução , clique no WHERE botão , que abre a caixa de diálogo Adicionar WHERE Cláusula (consulte Figura 2). Para adicionar um parâmetro para limitar os resultados retornados pela SELECT consulta, primeiro escolha a coluna para filtrar os dados. Em seguida, escolha o operador a ser usado para filtragem (=, <, <=, >e assim por diante). Por fim, escolha a origem do valor do parâmetro, como no estado querystring ou session. Depois de configurar o parâmetro, clique no botão Adicionar para incluí-lo na SELECT consulta.

Para este exemplo, vamos retornar apenas os resultados em que o UnitPrice valor é menor ou igual a US$ 25,00. Portanto, escolha UnitPrice na lista suspensa Coluna e <= na lista suspensa Operador. Ao usar um valor de parâmetro embutido em código (como US$ 25,00) ou se o valor do parâmetro for especificado programaticamente, selecione Nenhum na lista suspensa Origem. Em seguida, insira o valor do parâmetro embutido em código na caixa de texto Valor 25.00 e conclua o processo clicando no botão Adicionar.

Limitar os resultados retornados da caixa de diálogo Adicionar Cláusula WHERE

Figura 2: Limitar os resultados retornados da caixa de diálogo Adicionar WHERE Cláusula (Clique para exibir a imagem em tamanho real)

Depois de adicionar o parâmetro, clique em OK para retornar ao assistente Configurar Fonte de Dados. A SELECT instrução na parte inferior do assistente agora deve incluir uma WHERE cláusula com um parâmetro chamado @UnitPrice:

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

Observação

Se você especificar várias condições na WHERE cláusula da caixa de diálogo Adicionar WHERE Cláusula, o assistente as unirá ao AND operador . Se você precisar incluir um OR na WHERE cláusula (como WHERE UnitPrice <= @UnitPrice OR Discontinued = 1) , precisará compilar a SELECT instrução por meio da tela de instrução SQL personalizada.

Conclua a configuração do SqlDataSource (clique em Avançar e em Concluir) e inspecione a marcação declarativa do SqlDataSource. A marcação agora inclui uma <SelectParameters> coleção, que explica as fontes para os parâmetros no 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>

Quando o método sqlDataSource é Select() invocado, o valor do UnitPrice parâmetro (25,00) é aplicado ao @UnitPrice parâmetro no SelectCommand antes de ser enviado ao banco de dados. O resultado líquido é que apenas os produtos menores ou iguais a US$ 25,00 são retornados da Products tabela. Para confirmar isso, adicione um GridView à página, associe-o a essa fonte de dados e exiba a página por meio de um navegador. Você só deve ver os produtos listados que são menores ou iguais a US$ 25,00, como confirma a Figura 3.

Somente os produtos menores ou iguais a US$ 25,00 são exibidos

Figura 3: Somente os produtos menores ou iguais a US$ 25,00 são exibidos (clique para exibir a imagem em tamanho real)

Etapa 2: Adicionar parâmetros a uma instrução SQL personalizada

Ao adicionar uma instrução SQL personalizada, você pode inserir a WHERE cláusula explicitamente ou especificar um valor na célula Filter do Construtor de Consultas. Para demonstrar isso, vamos exibir apenas esses produtos em um GridView cujos preços são inferiores a um determinado limite. Comece adicionando um TextBox à ParameterizedQueries.aspx página para coletar esse valor de limite do usuário. Defina a propriedade MaxPriceTextBox como ID . Adicione um controle Web Button e defina sua Text propriedade como Exibir Produtos Correspondentes.

Em seguida, arraste um GridView para a página e, de sua marca inteligente, escolha criar um novo SqlDataSource chamado ProductsFilteredByPriceDataSource. No assistente Configurar Fonte de Dados, prossiga para a tela Especificar uma instrução SQL personalizada ou procedimento armazenado (consulte a Figura 4) e insira a seguinte consulta:

SELECT ProductName, UnitPrice
FROM Products
WHERE UnitPrice <= @MaximumPrice

Depois de inserir a consulta (manualmente ou por meio do Construtor de Consultas), clique em Avançar.

Retornar somente esses produtos menores ou iguais a um valor de parâmetro

Figura 4: retornar somente os produtos menores ou iguais a um valor de parâmetro (clique para exibir a imagem em tamanho real)

Como a consulta inclui parâmetros, a próxima tela do assistente nos solicita a origem dos valores de parâmetros. Escolha Controle na lista suspensa Origem do parâmetro e MaxPrice (o valor do ID controle TextBox) na lista suspensa ControlID. Você também pode inserir um valor padrão opcional a ser usado no caso em que o usuário não inseriu nenhum texto no MaxPrice TextBox. Por enquanto, não insira um valor padrão.

A propriedade de texto MaxPrice TextBox é usada como a origem do parâmetro

Figura 5: a MaxPrice propriedade TextBox s Text é usada como a origem do parâmetro (clique para exibir a imagem em tamanho real)

Conclua o assistente Configurar Fonte de Dados clicando em Avançar e, em seguida, Concluir. A marcação declarativa para GridView, TextBox, Button e SqlDataSource segue:

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>

Observe que o parâmetro na seção SqlDataSource s <SelectParameters> é um ControlParameter, que inclui propriedades adicionais como ControlID e PropertyName. Quando o método sqlDataSource é Select() invocado, o ControlParameter pega o valor da propriedade de controle Web especificada e o atribui ao parâmetro correspondente no SelectCommand. Neste exemplo, a MaxPrice propriedade s Text é usada como o valor do @MaxPrice parâmetro.

Reserve um minuto para exibir esta página por meio de um navegador. Ao visitar a página pela primeira vez ou sempre que a MaxPrice Caixa de Texto não tem um valor, nenhum registro é exibido no GridView.

Nenhum registro é exibido quando a Caixa de Texto MaxPrice está vazia

Figura 6: Nenhum registro é exibido quando a MaxPrice Caixa de Texto está vazia (clique para exibir a imagem em tamanho real)

O motivo pelo qual nenhum produto é mostrado é porque, por padrão, uma cadeia de caracteres vazia para um valor de parâmetro é convertida em um valor de banco de dados NULL . Como a comparação de [UnitPrice] <= NULL sempre é avaliada como False, nenhum resultado é retornado.

Insira um valor na caixa de texto, como 5,00, e clique no botão Exibir Produtos Correspondentes. No postback, o SqlDataSource informa ao GridView que uma de suas fontes de parâmetro foi alterada. Consequentemente, o GridView é reassociado ao SqlDataSource, exibindo esses produtos menores ou iguais a US$ 5,00.

Produtos menores ou iguais a US$ 5,00 são exibidos

Figura 7: Produtos menores ou iguais a US$ 5,00 são exibidos (clique para exibir a imagem em tamanho real)

Inicialmente exibindo todos os produtos

Em vez de não exibir nenhum produto quando a página for carregada pela primeira vez, talvez queiramos exibir todos os produtos. Uma maneira de listar todos os produtos sempre que o MaxPrice TextBox estiver vazio é definir o valor padrão do parâmetro como um valor insanamente alto, como 10000000, pois é improvável que a Northwind Traders tenha estoque cujo preço unitário exceda US$ 1.000.000. No entanto, essa abordagem é miopia e pode não funcionar em outras situações.

Em tutoriais anteriores – Parâmetros Declarativos e Filtragem Mestre/Detalhes com uma DropDownList , enfrentamos um problema semelhante. Nossa solução era colocar essa lógica na Camada de Lógica de Negócios. Especificamente, a BLL examinou o valor de entrada e, se fosse NULL ou algum valor reservado, a chamada foi roteada para o método DAL que retornou todos os registros. Se o valor de entrada fosse um valor de filtragem normal, uma chamada foi feita para o método DAL que executou uma instrução SQL que usava uma cláusula parametrizada WHERE com o valor fornecido.

Infelizmente, ignoramos a arquitetura ao usar o SqlDataSource. Em vez disso, precisamos personalizar a instrução SQL para capturar de forma inteligente todos os registros se o @MaximumPrice parâmetro for NULL ou algum valor reservado. Para este exercício, vamos tê-lo para que, se o @MaximumPrice parâmetro for igual a -1.0, todos os registros sejam retornados (-1.0 funciona como um valor reservado, pois nenhum produto pode ter um valor negativo UnitPrice ). Para fazer isso, podemos usar a seguinte instrução SQL:

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

Essa WHERE cláusula retornará todos os registros se o parâmetro for igual -1.0a @MaximumPrice . Se o valor do parâmetro não -1.0for , somente os produtos cujo UnitPrice é menor ou igual ao valor do @MaximumPrice parâmetro serão retornados. Ao definir o valor padrão do @MaximumPrice parâmetro como -1.0, na primeira carga de página (ou sempre que o MaxPrice TextBox estiver vazio), @MaximumPrice terá um valor de -1.0 e todos os produtos serão exibidos.

Agora todos os produtos são exibidos quando a Caixa de Texto MaxPrice está vazia

Figura 8: Agora todos os produtos são exibidos quando a MaxPrice TextBox está vazia (clique para exibir a imagem em tamanho real)

Há algumas ressalvas a serem observadas com essa abordagem. Primeiro, perceba que o tipo de dados do parâmetro é inferido pelo uso dele na consulta SQL. Se você alterar a WHERE cláusula de @MaximumPrice = -1.0 para @MaximumPrice = -1, o runtime tratará o parâmetro como um inteiro. Se você tentar atribuir o MaxPrice TextBox a um valor decimal (como 5,00 ), ocorrerá um erro porque ele não poderá converter 5,00 em um inteiro. Para corrigir isso, certifique-se de usar @MaximumPrice = -1.0 na WHERE cláusula ou, melhor ainda, definir a ControlParameter propriedade do Type objeto como Decimal .

Em segundo lugar, ao adicionar o OR @MaximumPrice = -1.0 à WHERE cláusula , o mecanismo de consulta não pode usar um índice em UnitPrice (supondo que exista um), resultando assim em uma verificação de tabela. Isso poderá afetar o desempenho se houver um número suficientemente grande de registros na Products tabela. Uma abordagem melhor seria mover essa lógica para um procedimento armazenado em que uma instrução IF executasse uma SELECT consulta da Products tabela sem uma WHERE cláusula quando todos os registros precisassem ser retornados ou uma cuja WHERE cláusula contém apenas os UnitPrice critérios, para que um índice possa ser usado.

Etapa 3: Criando e usando procedimentos armazenados parametrizados

Os procedimentos armazenados podem incluir um conjunto de parâmetros de entrada que podem ser usados nas instruções SQL definidas dentro do procedimento armazenado. Ao configurar o SqlDataSource para usar um procedimento armazenado que aceita parâmetros de entrada, esses valores de parâmetro podem ser especificados usando as mesmas técnicas que com instruções SQL ad hoc.

Para ilustrar o uso de procedimentos armazenados no SqlDataSource, vamos criar um novo procedimento armazenado no banco de dados Northwind chamado GetProductsByCategory, que aceita um parâmetro chamado @CategoryID e retorna todas as colunas dos produtos cuja CategoryID coluna corresponde @CategoryIDa . Para criar um procedimento armazenado, acesse a Explorer servidor e faça uma busca detalhada no NORTHWND.MDF banco de dados. (Se você não vir o servidor Explorer, abra-o acessando o menu Exibir e selecionando a opção Servidor Explorer.)

NORTHWND.MDF No banco de dados, clique com o botão direito do mouse na pasta Procedimentos Armazenados, escolha Adicionar Novo Procedimento Armazenado e insira a seguinte sintaxe:

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

Clique no ícone Salvar (ou Ctrl+S) para salvar o procedimento armazenado. Você pode testar o procedimento armazenado clicando com o botão direito do mouse na pasta Procedimentos Armazenados e escolhendo Executar. Isso solicitará os parâmetros do procedimento armazenado (@CategoryID, nesta instância), após os quais os resultados serão exibidos na janela Saída.

O procedimento armazenado GetProductsByCategory quando executado com um <span class=@CategoryID de 1" />

Figura 9: o GetProductsByCategory procedimento armazenado quando executado com um @CategoryID de 1 (clique para exibir a imagem em tamanho real)

Vamos usar esse procedimento armazenado para exibir todos os produtos na categoria Bebidas em um GridView. Adicione um novo GridView à página e associe-o a um novo SqlDataSource chamado BeverageProductsDataSource. Continue na tela Especificar uma instrução SQL personalizada ou procedimento armazenado, selecione o botão de opção Procedimento armazenado e escolha o GetProductsByCategory procedimento armazenado na lista suspensa.

Selecione o Procedimento Armazenado GetProductsByCategory na Lista de Drop-Down

Figura 10: Selecione o GetProductsByCategory Procedimento Armazenado na Lista de Drop-Down (Clique para exibir a imagem em tamanho real)

Como o procedimento armazenado aceita um parâmetro de entrada (@CategoryID), clicar em Avançar nos solicita que especifique a origem desse valor de parâmetro. As Bebidas são 1, portanto, deixe a lista suspensa Origem do parâmetro em Nenhum e insira CategoryID 1 na caixa de texto DefaultValue.

Usar um valor de Hard-Coded de 1 para retornar os produtos na categoria bebidas

Figura 11: Usar um valor de Hard-Coded de 1 para retornar os produtos na categoria bebidas (clique para exibir a imagem em tamanho real)

Como mostra a marcação declarativa a seguir, ao usar um procedimento armazenado, a propriedade s SelectCommand SqlDataSource é definida como o nome do procedimento armazenado e a SelectCommandType propriedade é definida StoredProcedurecomo , indicando que o SelectCommand é o nome de um procedimento armazenado em vez de uma instrução 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>

Teste a página em um navegador. Somente os produtos que pertencem à categoria Bebidas são exibidos, embora todos os campos do produto sejam exibidos, pois o GetProductsByCategory procedimento armazenado retorna todas as colunas da Products tabela. É claro que poderíamos limitar ou personalizar os campos exibidos no GridView na caixa de diálogo Editar Colunas do GridView.

Todas as bebidas são exibidas

Figura 12: Todas as bebidas são exibidas (clique para exibir a imagem em tamanho real)

Etapa 4: Invocar programaticamente uma instrução Select() do SqlDataSource

Os exemplos que vimos no tutorial anterior e neste tutorial até agora associaram os controles SqlDataSource diretamente a um GridView. No entanto, os dados do controle SqlDataSource podem ser acessados e enumerados programaticamente no código. Isso pode ser particularmente útil quando você precisa consultar dados para inspecioná-los, mas não precisa exibi-los. Em vez de precisar escrever todo o código de ADO.NET clichê para se conectar ao banco de dados, especificar o comando e recuperar os resultados, você pode permitir que o SqlDataSource manipule esse código monótono.

Para ilustrar o trabalho com os dados do SqlDataSource programaticamente, imagine que seu chefe tenha abordado você com uma solicitação para criar uma página da Web que exibe o nome de uma categoria selecionada aleatoriamente e seus produtos associados. Ou seja, quando um usuário visita essa página, queremos escolher aleatoriamente uma categoria da Categories tabela, exibir o nome da categoria e, em seguida, listar os produtos que pertencem a essa categoria.

Para fazer isso, precisamos de dois controles SqlDataSource um para pegar uma categoria aleatória da Categories tabela e outro para obter os produtos da categoria. Criaremos o SqlDataSource que recupera um registro de categoria aleatório nesta etapa; A etapa 5 analisa a criação do SqlDataSource que recupera os produtos da categoria.

Comece adicionando um SqlDataSource a ParameterizedQueries.aspx e defina como RandomCategoryDataSourceID . Configure-o para que ele use a seguinte consulta SQL:

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

ORDER BY NEWID() retorna os registros classificados em ordem aleatória (consulte Usando NEWID() para classificar registros aleatoriamente). SELECT TOP 1 retorna o primeiro registro do conjunto de resultados. Juntas, essa consulta retorna os CategoryID valores de coluna e CategoryName de uma única categoria selecionada aleatoriamente.

Para exibir o valor da categoria, CategoryName adicione um controle Web Label à página, defina sua ID propriedade CategoryNameLabelcomo e desmarque sua Text propriedade. Para recuperar programaticamente os dados de um controle SqlDataSource, precisamos invocar seu Select() método. O Select() método espera um único parâmetro de entrada do tipo DataSourceSelectArguments, que especifica como os dados devem ser remetente antes de serem retornados. Isso pode incluir instruções sobre como classificar e filtrar os dados e é usado pelos controles da Web de dados ao classificar ou paginar os dados de um controle SqlDataSource. Porém, para nosso exemplo, não precisamos que os dados sejam modificados antes de serem retornados e, portanto, passaremos o DataSourceSelectArguments.Empty objeto .

O Select() método retorna um objeto que implementa IEnumerable. O tipo preciso retornado depende do valor da propriedade s do DataSourceModecontrole SqlDataSource. Conforme discutido no tutorial anterior, essa propriedade pode ser definida como um valor de DataSet ou DataReader. Se definido como DataSet, o Select() método retornará um objeto DataView ; se definido como DataReader, retornará um objeto que implementa IDataReader. Como o RandomCategoryDataSource SqlDataSource tem sua DataSourceMode propriedade definida DataSet como (o padrão), trabalharemos com um objeto DataView.

O código a seguir ilustra como recuperar os registros do RandomCategoryDataSource SqlDataSource como um DataView, bem como ler o CategoryName valor da coluna da primeira linha DataView:

protected void Page_Load(object sender, EventArgs e)
{
    // Get the data from the SqlDataSource as a DataView
    DataView randomCategoryView =
        (DataView)RandomCategoryDataSource.Select(DataSourceSelectArguments.Empty);
    if (randomCategoryView.Count > 0)
    {
        // Assign the CategoryName value to the Label
        CategoryNameLabel.Text =
            string.Format("Here are Products in the {0} Category...",
                randomCategoryView[0]["CategoryName"].ToString());
    }
}

randomCategoryView[0] retorna o primeiro DataRowView no DataView. randomCategoryView[0]["CategoryName"] retorna o valor da CategoryName coluna nesta primeira linha. Observe que o DataView é de tipo flexível. Para fazer referência a um valor de coluna específico, precisamos passar o nome da coluna como uma cadeia de caracteres ( CategoryName, nesse caso). A Figura 13 mostra a mensagem exibida no CategoryNameLabel ao exibir a página. É claro que o nome real da categoria exibido é selecionado aleatoriamente pelo RandomCategoryDataSource SqlDataSource em cada visita à página (incluindo postbacks).

O nome da categoria selecionada aleatoriamente é exibido

Figura 13: o nome da categoria selecionada aleatoriamente é exibido (clique para exibir a imagem em tamanho real)

Observação

Se a propriedade s do DataSourceMode controle SqlDataSource tivesse sido definida DataReadercomo , o valor retornado do Select() método precisaria ser convertido em IDataReader. Para ler o CategoryName valor da coluna da primeira linha, usaríamos código como:

if (randomCategoryReader.Read())
{
   string categoryName = randomCategoryReader["CategoryName"].ToString();
   ...
}

Com o SqlDataSource selecionando aleatoriamente uma categoria, estamos prontos para adicionar o GridView que lista os produtos da categoria.

Observação

Em vez de usar um controle Web Label para exibir o nome da categoria, poderíamos ter adicionado um FormView ou DetailsView à página, associando-o ao SqlDataSource. No entanto, o uso do Rótulo nos permitiu explorar como invocar programaticamente a instrução sqlDataSource Select() e trabalhar com seus dados resultantes no código.

Etapa 5: Atribuindo valores de parâmetro programaticamente

Todos os exemplos que vimos até agora neste tutorial usaram um valor de parâmetro embutido em código ou um obtido de uma das fontes de parâmetro predefinidas (um valor querystring, um controle da Web na página e assim por diante). No entanto, os parâmetros do controle SqlDataSource também podem ser definidos programaticamente. Para concluir nosso exemplo atual, precisamos de um SqlDataSource que retorne todos os produtos pertencentes a uma categoria especificada. Esse SqlDataSource terá um CategoryID parâmetro cujo valor precisa ser definido com base no valor da CategoryID coluna retornado pelo RandomCategoryDataSource SqlDataSource no Page_Load manipulador de eventos.

Comece adicionando um GridView à página e associe-o a um novo SqlDataSource chamado ProductsByCategoryDataSource. Assim como fizemos na Etapa 3, configure o SqlDataSource para que ele invoque o GetProductsByCategory procedimento armazenado. Deixe a lista suspensa Origem do parâmetro definida como Nenhum, mas não insira um valor padrão, pois definiremos esse valor padrão programaticamente.

Captura de tela mostrando a janela Configurar Fonte de Dados com a origem do parâmetro definida como Nenhum.

Figura 14: Não especificar uma fonte de parâmetro ou valor padrão (clique para exibir a imagem em tamanho real)

Depois de concluir o assistente sqlDataSource, a marcação declarativa resultante deve ser semelhante à seguinte:

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

Podemos atribuir o DefaultValueCategoryID do parâmetro programaticamente no Page_Load manipulador de eventos:

// Assign the ProductsByCategoryDataSource's
// CategoryID parameter's DefaultValue property
ProductsByCategoryDataSource.SelectParameters["CategoryID"].DefaultValue =
    randomCategoryView[0]["CategoryID"].ToString();

Com essa adição, a página inclui um GridView que mostra os produtos associados à categoria selecionada aleatoriamente.

Captura de tela mostrando a página Sua Categoria Selecionada Aleatoriamente.

Figura 15: Não especificar uma fonte de parâmetro ou valor padrão (clique para exibir a imagem em tamanho real)

Resumo

O SqlDataSource permite que os desenvolvedores de página definam consultas parametrizadas cujos valores de parâmetro podem ser codificados, extraídos de fontes de parâmetro predefinidas ou atribuídos programaticamente. Neste tutorial, vimos como criar uma consulta parametrizada do assistente Configurar Fonte de Dados para consultas SQL ad hoc e procedimentos armazenados. Também examinamos o uso de fontes de parâmetro embutidas em código, um controle web como uma fonte de parâmetro e especificando programaticamente o valor do parâmetro.

Assim como no ObjectDataSource, o SqlDataSource também fornece recursos para modificar seus dados subjacentes. No próximo tutorial, veremos como definir INSERTinstruções , UPDATEe DELETE com o SqlDataSource. Depois que essas instruções tiverem sido adicionadas, poderemos utilizar os recursos internos de inserção, edição e exclusão inerentes aos controles GridView, DetailsView e FormView.

Programação feliz!

Sobre o autor

Scott Mitchell, autor de sete livros do ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias da Microsoft Web desde 1998. Scott trabalha como consultor independente, treinador e escritor. Seu último livro é Sams Teach Yourself ASP.NET 2.0 em 24 Horas. Ele pode ser contatado em mitchell@4GuysFromRolla.com. ou através de seu blog, que pode ser encontrado em http://ScottOnWriting.NET.

Agradecimentos Especiais

Esta série de tutoriais foi revisada por muitos revisores úteis. Os principais revisores deste tutorial foram Scott Clyde, Randell Schmidt e Ken Pespisa. Interessado em revisar meus próximos artigos do MSDN? Nesse caso, solte-me uma linha em mitchell@4GuysFromRolla.com.