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.
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:
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:
- Definimos a string de conexão
- Criamos o comando cmdOrder
- Abrimos a conexão
- Criamos o DataReader drOrder sobre o comando cmdOrder
- Percorremos o DataReader drOrder
- Exibimos o no. do pedido e a cidade
- Criamos o comando cmdDetail
- Definimos um novo DataReader drDetail no comando cmdDetail
- 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 aqui: MultiplosComandos_PorConexao.zip