ADO .NET - Executando Múltiplos Comandos em uma única conexão


Se você usa o objeto DataReader em seus aplicativos e tentou utilizar mais de um comando em uma conexão aberta já deve ter visto a mensagem de erro : "There is already an open DataReader associated with this Command which must be closed first." ("Já existe um DataReader aberto associado a esta conexão que deve ser fechado...." )

Então não posso executar mais de um comando em uma mesma conexão ???

Pode, mas para isso você tem que ativar o recurso MARS - Multiple Active Result Sets.

O recurso MARS possibilita abrir múltiplos objetos SqlDataReader em uma única conexão. Ele permite que um aplicativo tenha mais de um SqlDataReader aberto em uma conexão quando cada instância do SqlDataReader é iniciada a partir de um comando separado. Cada objeto SqlCommand que você adicionar acrescenta uma sessão adicional para a conexão.

O recurso MARS está disponível em muitos SGBDs, sendo que o SQL Server 2005 foi o primeiro a dar suporte ao MARS. Você pode controlar explicitamente a ativação do recurso utilizando um par de palavras-chave em sua seqüência de conexão. Para ativar o recurso MARS em sua conexão você define explicitamente o atributo MultipleActiveResultSets na seqüência de conexão para True da seguinte forma:

string northwindConnectionString = "Server=localhost;Database=Northwind;Trusted_Connection=True;MultipleActiveResultSets=True";

Vou mostrar um exemplo prático usando os seguintes recursos:

Criando o projeto

Neste projeto exemplo vamos abrir dois DataReader usando dois comandos na mesma conexão:

Vamos criar um novo projeto no Visual C# 2010 Express Edition acionando o menu File -> New Project e a seguir escolhendo o template Windows Forms Application;

Informe o nome MultiplosComandos_PorConexao e clique no botão OK;

A seguir abra a janela Database Explorer e clique no ícone Data Connections com o botão direito do mouse e selecione Add Connections;

Na janela Add Connection escolha o Data Source - Microsoft SQL Server Database File (SqlClient) - e informe o local do banco de dados Northwind.mdf;

Obs: Eu estou anexando o banco de dados Northwind.mdf no meu SQL Server.

Após clicar no botão OK você deverá ter acesso a todos os objetos do banco de dados Northwind.mdf no SQL Server.

No formulário padrão form1.cs inclua os seguintes controles:

Disponha os controles conforme o leiaute da figura a seguir:

Vamos declarar os seguintes namespaces no inicio do formulário:

using System;
using System.Windows.Forms;
using System.Data.SqlClient;

Vamos definir a string de conexão e ativar o recurso MARS :

string sqlConnectString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=C:\dados\Northwind.MDF;Integrated Security=True;Connect Timeout=30;User Instance=True;MultipleActiveResultSets=True";

O código do evento Click do botão Executar é mostrado a seguir:


        private void btnExecutar_Click(object sender, EventArgs e)
        {
            string sqlConnectString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=C:\dados\Northwind.MDF;Integrated Security=True;Connect Timeout=30;User Instance=
True;MultipleActiveResultSets=True";

            SqlConnection connection = new SqlConnection(sqlConnectString);

        
   // cria o DataReader com 3 registros da tabela Orders
            SqlCommand cmdOrder = connection.CreateCommand();
            cmdOrder.CommandText ="SELECT TOP 5 OrderID, OrderDate,ShipCity FROM Orders";
            connection.Open();
            SqlDataReader drOrder = cmdOrder.ExecuteReader();

        
   // Percorre o reader com os registros dos pedidos
            while (drOrder.Read())
            {
                lstDados.Items.Add("Pedido ID : " + drOrder["OrderID"] + " Cidade : " + drOrder["ShipCity"]);

              
 // Cria um DataReader com os detalhes do pedido
                SqlCommand cmdDetail = connection.CreateCommand();
                cmdDetail.CommandText = "SELECT ProductID, Quantity FROM [Order Details] WHERE OrderID=" + drOrder["OrderID"];
           
    // percorre os detalhes do pedido para o pedido

                using (SqlDataReader drDetail = cmdDetail.ExecuteReader())
                {
                    while (drDetail.Read())
                    {
                        lstDados.Items.Add("\tProduto ID : " + drDetail["ProductID"] + "\tQuantidade : " + drDetail["Quantity"]);
                    }
                    lstDados.Items.Add("-------------------------------------------------------------------");
                    drDetail.Dispose();
                }
            }
            connection.Close();
        }
    }

No código acima temos o seguinte:

  1. Definimos a string de conexão
  2. Criamos o comando cmdOrder
  3. Abrimos a conexão
  4. Criamos o DataReader drOrder sobre o comando cmdOrder
  5. Percorremos o DataReader drOrder
  6. Exibimos o no. do pedido e a cidade
  7. Criamos o comando cmdDetail
  8. Definimos um novo DataReader drDetail no comando cmdDetail
  9. Percorremos o DataReader drDetail e exibimos os detalhes do pedido

Executando o projeto iremos obter o seguinte resultado:

O exemplo mostra que ativando o recurso MARS podemos usar mais de um comando em uma única conexão.

Pegue o projeto completo aquiMultiplosComandos_PorConexao.zip

Mat 3:11 Eu (João Batista), na verdade, vos batizo em água, na base do arrependimento; mas aquele (Jesus)  que vem após mim é mais poderoso do que eu, que nem sou digno de levar-lhe as alparcas; ele vos batizará no Espírito Santo, e em fogo.

Mat 3:12 A sua pá ele tem na mão, e limpará bem a sua eira; recolherá o seu trigo ao celeiro, mas queimará a palha em fogo inextinguível.

Referências:


José Carlos Macoratti