web-dev-qa-db-fra.com

erreur 'il y a déjà un datareader ouvert associé à cette commande qui doit être fermé en premier'

erreur d'exécution "il y a déjà un datareader ouvert associé à cette commande qui doit être fermé en premier"

objCommand = new SqlCommand("SELECT field1, field2 FROM sourcetable", objConn);

objDataReader = objCommand.ExecuteReader();

while (objDataReader.Read())
{
objInsertCommand = new SqlCommand("INSERT INTO tablename (field1, field2) VALUES (3, '" + objDataReader[0] + "')", objConn);
objInsertCommand.ExecuteNonQuery();//Here is the error
}
objDataReader.Close();

Je ne peux définir aucune procédure stockée ici . Toute aide serait appréciée.

24
Pradeep

Pourquoi ne pas extraire les données dans un DataSet via Fill puis les parcourir pour effectuer votre insertion via NonQuery?

IDbDataAdapter da;
IDbCommand selectCommand = connection.CreateCommand();
selectCommand.CommandType = CommandType.Text;
selectCommand.CommandText = "SELECT field1, field2 FROM sourcetable";
connection.Open();
DataSet selectResults= new DataSet();
da.Fill(selectResults); // get dataset
selectCommand.Dispose();
IDbCommand insertCommand;

foreach(DataRow row in selectResults.Tables[0].Rows)
{
    insertCommand = connection.CreateCommand();
    insertCommand.CommandType = CommandType.Text;
    insertCommand.CommandText = "INSERT INTO tablename (field1, field2) VALUES (3, '" + row["columnName"].ToString() + "'";   
}
insertCommand.Dispose();
connection.Close();
6
Brad

Pas besoin de faire tout cela, il suffit d’allumer MARS et votre problème sera résolu. Dans votre chaîne de connexion, ajoutez simplement MultipleActiveResultSets=True;

80
ali

Vous ne pouvez pas effectuer d'action sur cette connexion tant qu'elle lit le contenu d'un lecteur de données. L'erreur est assez descriptive.

Vos alternatives sont:

1) Récupérez d’abord toutes vos données, soit avec un DataSet, soit utilisez le lecteur pour créer une autre collection, puis exécutez-les toutes en une fois après la sélection initiale.

2) Utilisez une connexion différente pour vos instructions d'insertion.

7
Joe Enos

Votre meilleur choix serait de lire les informations dont vous avez besoin dans une liste, puis de la réitérer pour effectuer vos insertions comme suit:

        List<String> values = new List<String>();
        using(SqlCommand objCommand = new SqlCommand("SELECT field1, field2 FROM sourcetable", objConn)) {
            using(SqlDataReader objDataReader = objCommand.ExecuteReader()) {
                while(objDataReader.Read()) {
                    values.Add(objDataReader[0].ToString());
                }
            }
        }
        foreach(String value in values) {
            using(SqlCommand objInsertCommand = new SqlCommand("INSERT INTO tablename (field1, field2) VALUES (3, '" + value + "')", objConn)) {
                objInsertCommand.ExecuteNonQuery();
            }
        }
4
Steve Ellinger
INSERT INTO tablename (field1, field2)
    SELECT 3, field1 FROM sourcetable

Une seule instruction SQL au lieu d'une par insertion. Vous ne savez pas si cela fonctionnera pour votre problème réel, mais pour l'exemple que vous avez fourni, il s'agit d'une requête bien meilleure que de les traiter un par un.

Par ailleurs, assurez-vous que votre code utilise des requêtes paramétrées au lieu d'accepter les chaînes telles quelles dans l'instruction SQL - votre exemple est ouvert à l'injection SQL.

3
Joe Enos

Plusieurs suggestions ont été données qui fonctionnent très bien, ainsi que des recommandations pour améliorer la mise en œuvre. J'ai atteint la limite de MARS car le code existant ne nettoie pas le lecteur. Je voulais donc constituer un échantillon plus respectable:

const string connectionString = @"server=.\sqlexpress;database=adventureworkslt;integrated security=true";
const bool useMARS = false;
using (var objConn = new System.Data.SqlClient.SqlConnection(connectionString + (useMARS ? ";MultipleActiveResultSets=True" : String.Empty)))
using (var objInsertConn = useMARS ? null : new System.Data.SqlClient.SqlConnection(connectionString))
{
 objConn.Open();
 if (objInsertConn != null)
 {
  objInsertConn.Open();
 }

 using (var testCmd = new System.Data.SqlClient.SqlCommand())
 {
  testCmd.Connection = objConn;
  testCmd.CommandText = @"if not exists(select 1 from information_schema.tables where table_name = 'sourcetable')
                          begin
                           create table sourcetable (field1 int, field2 varchar(5))
                           insert into sourcetable values (1, 'one')
                           create table tablename (field1 int, field2 varchar(5))
                          end";
  testCmd.ExecuteNonQuery();
 }

 using (var objCommand = new System.Data.SqlClient.SqlCommand("SELECT field1, field2 FROM sourcetable", objConn))
 using (var objDataReader = objCommand.ExecuteReader())
 using (var objInsertCommand = new System.Data.SqlClient.SqlCommand("INSERT INTO tablename (field1, field2) VALUES (3, @field2)", objInsertConn ?? objConn))
 {
  objInsertCommand.Parameters.Add(new System.Data.SqlClient.SqlParameter("field2", String.Empty));
  while (objDataReader.Read())
  {
   objInsertCommand.Parameters[0].Value = objDataReader[0];
   objInsertCommand.ExecuteNonQuery();
  }
 }
}
2
user423430

Ajouter ceci à la chaîne de connexion devrait résoudre le problème.

MultipleActiveResultSets=true
1
Jaanus

Option 1: Vous devez exécuter la requête et charger les données avant d'exécuter une autre requête.

Option 2: Ajoutez MultipleActiveResultSets=true à la partie fournisseur de votre chaîne de connexion. Voir l'exemple ci-dessous:

<add name="DbContext" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=dbName;Persist Security Info=True;User ID=userName;Password=password;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
1
Md. Rousonur Jaman

Quelle version de SQL Server utilisez-vous? Le problème pourrait être avec ceci:

(from http://msdn.Microsoft.com/en-us/library/9kcbe65k.aspx )

Lorsque vous utilisez des versions de SQL Server antérieures à SQL Server 2005, alors que SqlDataReader est utilisé, le SqlConnection associé est occupé à servir le SqlDataReader. Dans cet état, aucune opération ne peut être effectuée sur la connexion SqlConnection autre que sa fermeture. C'est le cas jusqu'à ce que la méthode Close du SqlDataReader soit appelée.

Donc, si c’est ce qui cause votre problème, vous devez d’abord lire toutes les données, puis fermer le SqlDataReader, et ensuite seulement exécuter vos insertions.

Quelque chose comme:

objCommand = new SqlCommand("SELECT field1, field2 FROM sourcetable", objConn);

objDataReader = objCommand.ExecuteReader();

List<object> values = new List<object>();
while (objDataReader.Read())
{
    values.Add(objDataReader[0]);
}

objDataReader.Close();

foreach (object value in values)
{
    objInsertCommand = new SqlCommand("INSERT INTO tablename (field1, field2) VALUES (3, '" + value + "')", objConn);
    objInsertCommand.ExecuteNonQuery();
}
1
Dan Dumitru

Pour pouvoir le jeter facilement, j'utilise le modèle de codage suivant:

`using (SqlConnection connection = new SqlConnection("your connection string"))
        {
            connection.Open();
            using (SqlCommand cmd = connection.CreateCommand())
            {
                cmd.CommandText = "Select * from SomeTable";
                using (SqlDataReader reader = cmd.ExecuteReader())
                {

                    if(reader.HasRows)
                    { 
                       while(reader.Read()){
                       // assuming that we've a 1-column(Id) table 
                       int id = int.Parse(reader[0].ToString()); 

                       }
                    }
                }
            } 
            connection.Close()
        }`
0
Ahmet Gokdayi

Essayez quelque chose comme ça:

//Add a second connection based on the first one
SqlConnection objConn2= new SqlConnection(objConn.connectionString))

SqlCommand objInsertCommand= new SqlCommand();
objInsertCommand.CommandType = CommandType.Text;
objInsertCommand.Connection = objConn2;

while (objDataReader.Read())
{
    objInsertCommand.CommandText = "INSERT INTO tablename (field1, field2) VALUES (3, '" + objDataReader[0] + "')";
    objInsertCommand.ExecuteNonQuery();
}
0
David Aleu

Meilleure solution: Il n’ya qu’un problème avec votre valeur "CommandText". Soit SP ou Sql Query normal.

  • Contrôle 1: la valeur du paramètre que vous transmettez dans votre requête SQL ne change pas et reste identique encore et encore dans votre ExecuteReader.

  • Contrôle 2: la chaîne de requête SQL est mal formée.

  • Contrôle 3: Veuillez créer le code le plus simple comme suit.

    string ID = "C8CA7EE2";
    string myQuery = "select * from ContactBase where contactid=" + "'" + ID + "'";
    string connectionString = ConfigurationManager.ConnectionStrings["CRM_SQL_CONN_UAT"].ToString(); 
    SqlConnection con = new SqlConnection(connectionString);
    con.Open();
    SqlCommand cmd = new SqlCommand(myQuery, con);
    DataTable dt = new DataTable();
    dt.Load(cmd.ExecuteReader());
    con.Close();
    
0
Kush Kant Dayal Pune