.NET

10 jun, 2013

ADO .NET – Executando múltiplos comandos em uma única conexão

Publicidade

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 sequência de conexão. Para ativar o recurso MARS em sua conexão, você define explicitamente o atributo MultipleActiveResultSets na sequê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:

  • Visual C# 2010 Express Edition
  • SQL Server 2008 Express Edition
  • Banco de dados Northwind.mdf (attached)

Criando o projeto

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

  • Comando cmdOrder e DataReader drOrder – Obtém os 5 primeiros pedidos da tabela Orders;
  • Comando cmdDetail e DataReader drDetail – Obtém os detalhes do pedido para cada pedido na tabela Order Details.

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.

net_pag1

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:

  • ListBox – lstDados
  • Button – btnExecutar e btnEncerrar

Disponha os controles conforme o leiaute da figura a seguir:

adn_mcc1

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:

adn_mcc2

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

Pegue o projeto completo aqui: MultiplosComandos_PorConexao.zip