ADO.NET 2.0 - Usando SQLDataReader com Múltiplos Resultsets


Geralmente usamos um DataReader para preencher caixas de listas ou caixas de combinação com dados de uma tabela de consulta. Podemos estender este conceito usando múltiplos resultsets através de uma simples consulta em lote ou de um procedimento armazenado para preencher mais de um controle em um formulário.

Imagine que você tenha que preencher duas caixas de listagem : uma para clientes e outra para Estados em um formulário Windows.

Que tal se você pudesse efetuar tal tarefa usando um DataReader para selecionar os dados das tabelas correspondentes de uma única vez sem ter que abrir/fechar/abrir a conexão. É isto que vou  mostrar neste artigo.

O recurso de trabalhar com múltiplos resultsets (conjuntos de registros) não é novo, ele já existia nas versões anteriores do SQL Server (network Libraries) . Ocorre que na versão do SQL Server 2005 houve uma otimização na forma de como tratar isto e foi introduzido o MARS - Multiple Active ResultSets. (Lembrando que o Access não suporta este recurso).

Neste artigo eu vou usar o Visual Basic 2005 Express e o SQL Server 2005 Express que você pode baixar de graça no site da Microsoft.

Vou usar o banco de dados Cadastro.mdf que foi criado em artigos anteriores. Para que ninguém fique perdido segue abaixo como criar este banco de dados e a tabela Clientes no VB 2005:

Criando a base de dados no SQL Server 2005 Express

- Abra o VB 2005 Express Edition e crie um novo projeto chamado AdoNet_objBD1.

- Se a janela Data Sources não estiver visível Ative-a no menu Data->Show Data Sources.

- Clique no link Add New Data Source e na janela Data Source Configuration Wizard selecione DataBase.

Nota:  Poderíamos criar a base de dados clicando o botão direito do mouse sobre o nome do projeto e selecione Add->New Item  e na janela de templates selecionar o item SQL Database informando o nome cadastro.mdf para a base de dados a ser criada.

Clique no botão Next> na caixa de combinação selecione a conexão com a base cadastro.mdf. Expandindo a Connection String você verá a string de conexão que será usada para a conexão.

Ao clicar no botão Next> irá surgir a seguinte mensagem de aviso. Ela pergunta se você deseja copiar o arquivo da base de dados cadastro.mdf para o seu projeto. Clique em Não(No) para não salvar o arquivo no seu projeto usando assim o local original onde o mesmo foi criado.

Nota: Veja artigo VB.NET  2005 -  TableAdapater não atualiza os dados  para maiores detalhes sobre o assunto.

Clicando no botão Next> o próximo passo será salvar a string de conexão no arquivo de configuração da aplicação.(Você pode ver a o valor clicando em My Project ->Settings)

Neste ponto você deve clicar no botão Cancel para cancelar a operação pois não vamos criar um Data Source. Fizemos os passos acima somente para criar a base de dados e obter a string de conexão.

Criando a tabela Clientes

A próxima etapa será criar uma nova tabela chamada Clientes na base de dados cadastro.mdf.

- Abra a janela do DataBase Explorer e expanda os objetos para a conexão Cadastro.mdf.

- Selecione a opção Table e clique com o botão direito do mouse selecionando a opção Add New Table

 

A seguir informe conforme a figura abaixo os nomes dos campos e o tipo de dados. Ao terminar, salve o trabalho. Retornando a janela DataBase Explorer veremos a tabela Clientes e seus respectivos campos criados.

Se desejar pode incluir valores diretamente na tabela. Para isto clique sobre a tabela Clientes e selecione a opção Show Data Table.

Crie a tabela Estados da mesma forma com  a seguinte estrutura:

Estrutura da tabela Estados do banco de dados Cadastro.mdf.

Aproveite e inclua alguns dados na tabela Estados.

Já temos o projeto,  o banco de dados Cadastro.mdf e as tabelas Clientes e Estados. Vamos agora obter a string de conexão com o banco de dados e salvá-la no recurso My.Settings.

A string de conexão com o banco de dados usada será armazenada usando o recurso My.Settings conforme os seguintes passos:

  1. Clique com o botão direito sobre My Project na janela Solution Explorer e selecione Open.
  2. Na janela a seguir selecione Settings e informe um nome para a string de conexão e para a string SQL na coluna Name. Eu usei os nomes connSQL. Salve a operação. Pronto ! já podemos recuperar esta informação a partir de My.Settings em tempo de execução.

Altere o nome formulário padrão form1.vb  para frmObjDr.vb e inclua dois controles ListBox : lstClientes e lstEstados e um botão de comando btnExecDr conforme leiaute abaixo:

Define a seguinte importação no código do formulário:

Option Explicit On
Option
Strict On
Imports
System.Data
Imports
System.Data.SqlClient

Agora no evento Click do botão de comando vamos incluir uma chamara a rotina abrirDataReader()

Private Sub btnExecDr_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExecDr.Click

'chama a rotina para abrir o DataReader
abrirDataReader()

End Sub

Abaixo temos o código da rotina abrirDataReader() :

Private Sub abrirDataReader()
 

'Define e abre um objeto SqlConnection

Dim cnnCadastro As SqlConnection = New SqlConnection(My.Settings.connSQL)


Try

   cnnCadastro.Open()

   'Define o SqlCommand para abrir dois Resultsets : Clientes e Estados

   Dim strSQL As String = "SELECT * FROM Estados"
         strSQL +=
";SELECT Codigo, Nome, Cidade, Estado FROM Clientes"
 

   Dim cmdReader As SqlCommand = New SqlCommand(strSQL, cnnCadastro)

   cmdReader.CommandType = CommandType.Text
 

   'Define, cria, e traverse o SqlDataReader

   'Fecha a conex'ao quando fechar o SqlDataReader

   Dim drReader As SqlDataReader = cmdReader.ExecuteReader(CommandBehavior.CloseConnection)
 

   With drReader

      If .HasRows Then

         While .Read

             'Processa linhas iniciais : codigo (0) e nome do cliente (1)

             lstClientes.Items.Add(.Item(0).ToString + " - " + .Item(1).ToString)

        End While
 

        While .NextResult

            'Processa rowsets adicionais

            While .Read

               'Processa linhas adicionais : Codigo (0) - Nome do estado (1)

                lstUF.Items.Add(.Item(0).ToString + " - " + .Item(1).ToString + " " + .Item(2).ToString)

             End While

         End While

     End If

     'Fecha o sqlDataReader e o SqlConnection

     .Close()

  End With

Catch ex As Exception

   MsgBox(ex.Message)

End Try


End
Sub

No código acima estamos obtendo em um única conexão dois conjuntos de registros via objeto SQLCommand : um para a tabela Estados e outro para a tabela Clientes.

O argumento - CommandBehavior.CloseConnection - fecha a conexão quando o DataReader for fechado

Ao percorrer os registros no DataReader lembre-se que o método Read do SQLDataReader, que substitui o antigo movenext, retorna True enquanto existirem linhas a serem lidas.

O método NextResultSet do objeto SQLDataReader retorna True se existir um resultset ainda não totalmente processado.

A seguir percorremos cada resultset e preenchemos as caixas de listagem com os dados obtidos conforme exibido na figura abaixo:

Nota: Somente um resultset é aberto enquanto interagimos com múltiplos resultsets. O Recurso MARS do SQL Server 2005 permite processar os resultsets selecionados.

Pegue o código do projeto aqui:  AdoNet_objBD1.zip.

Bom estudo e até o próximo artigo ASP.NET...


José Carlos Macoratti