Подтвердить что ты не робот

Error 'уже есть открытый datareader, связанный с этой командой, который должен быть закрыт первым'

ошибка времени выполнения 'уже есть открытый datareader, связанный с этой командой, который должен быть закрыт первым'

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();

Я не могу определить какую-либо хранимую процедуру здесь. Любая помощь была бы оценена нами.

4b9b3361

Ответ 1

Как насчет того, чтобы вытащить данные в DataSet через Fill, а затем повторить это, чтобы выполнить вставку через 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();

Ответ 2

не нужно делать все это, просто включите MARS, и ваша проблема будет решена, в вашей строке подключения просто добавьте "MultipleActiveResultSets = True;"

Ответ 3

Вы не можете выполнить действие над этим соединением, пока он все еще работает над чтением содержимого устройства чтения данных - ошибка довольно описательная.

Ваши альтернативы:

1) Сначала извлеките все свои данные, либо с помощью DataSet, либо используйте считыватель для заполнения какой-либо другой коллекции, а затем запустите их сразу после завершения первоначального выбора.

2) Для ваших инструкций вставки используйте другое соединение.

Ответ 4

Лучше всего было бы прочитать нужную вам информацию в списке, а затем повторить список, чтобы выполнить ваши вставки так:

        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();
            }
        }

Ответ 5

INSERT INTO tablename (field1, field2)
    SELECT 3, field1 FROM sourcetable

Единая инструкция SQL вместо одной вставки. Не уверен, что это будет работать для вашей реальной проблемы, но для примера, который вы предоставили, это гораздо лучший вопрос, чем выполнение по одному за раз.

На стороне примечания убедитесь, что ваш код использует параметризованные запросы вместо того, чтобы принимать строки как есть внутри оператора SQL - ваш образец открыт для SQL-инъекции.

Ответ 6

Было предложено несколько предложений, которые отлично справляются с рекомендациями по улучшению реализации. Я ударил ограничение MARS из-за существующего кода, не очищающего считыватель, поэтому я хотел собрать более респектабельный образец:

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();
  }
 }
}

Ответ 7

Какую версию SQL Server вы используете? Проблема может быть в этом:

(из http://msdn.microsoft.com/en-us/library/9kcbe65k.aspx)

Когда вы используете версии SQL Server до SQL Server 2005, а SqlDataReader используется, связанный SqlConnection занят службой SqlDataReader. Хотя в этом состоянии никакие другие операции не могут выполняться в SqlConnection, кроме закрытия. Это происходит до тех пор, пока не вызывается метод Close для SqlDataReader.

Итак, если это то, что вызывает вашу проблему, вы должны сначала прочитать все данные, а затем закрыть SqlDataReader и только после этого выполнить свои вставки.

Что-то вроде:

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();
}

Ответ 8

Добавление этого в строку подключения должно устранить проблему.

MultipleActiveResultSets=true

Ответ 9

Вариант 1: Необходимо выполнить запрос и загрузить данные перед запуском другого запроса.

Вариант 2:  Добавьте MultipleActiveResultSets=true к стороне поставщика вашей строки подключения. См. Пример ниже:

<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" />

Ответ 10

Попробуйте что-то вроде этого:

//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();
}

Ответ 11

Лучшее решение: Существует только проблема с вашим значением "CommandText". Пусть это SP или обычный запрос Sql.

  • Проверить 1: значение параметра, которое вы передаете в запросе Sql не меняется и не повторяется снова и снова в вашем ExecuteReader.

  • Проверка 2: Строка запроса Sql неверно сформирована.

  • Проверка 3: Пожалуйста, создайте простейший код следующим образом.

    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();
    

Ответ 12

Для удобства использования я использую следующий шаблон кодирования:

`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()
        }`