61

I have below code and I am getting exception:

There is already an open DataReader associated with this Connection which must be closed first.

I am using Visual Studio 2010/.Net 4.0 and MySQL for this project. Basically I am trying to run another SQL statement while using data reader to do my other task. I am getting exception at line cmdInserttblProductFrance.ExecuteNonQuery();

SQL = "Select * from tblProduct";

//Create Connection/Command/MySQLDataReader
MySqlConnection myConnection = new MySqlConnection(cf.GetConnectionString());
myConnection.Open();
MySqlCommand myCommand = new MySqlCommand(SQL, myConnection);
MySqlDataReader myReader = myCommand.ExecuteReader();
myCommand.Dispose();

if (myReader.HasRows)
{
    int i = 0;
    // Always call Read before accessing data.
    while (myReader.Read())
    {
        if (myReader["frProductid"].ToString() == "") //there is no productid exist for this item
        {
            strInsertSQL = "Insert Into tblProduct_temp (Productid) Values('this istest') ";
            MySqlCommand cmdInserttblProductFrance = new MySqlCommand(strInsertSQL, myConnection);
            cmdInserttblProductFrance.ExecuteNonQuery(); //<=====THIS LINE THROWS "C# mySQL There is already an open DataReader associated with this Connection which must be closed first."
        }
    }
}
BartoszKP
  • 34,786
  • 15
  • 102
  • 130
Lord OfTheRing
  • 1,097
  • 3
  • 12
  • 20
  • The error message I see is '... associated with this **command** ...', I guess the message is wrong and this post explains that – JonnyRaa May 13 '15 at 14:10

11 Answers11

54

You are using the same connection for the DataReader and the ExecuteNonQuery. This is not supported, according to MSDN:

Note that while a DataReader is open, the Connection is in use exclusively by that DataReader. You cannot execute any commands for the Connection, including creating another DataReader, until the original DataReader is closed.

Updated 2018: link to MSDN

David Suarez
  • 1,090
  • 11
  • 12
38

Always, always, always put disposable objects inside of using statements. I can't see how you've instantiated your DataReader but you should do it like this:

using (Connection c = ...)
{
    using (DataReader dr = ...)
    {
        //Work with dr in here.
    }
}
//Now the connection and reader have been closed and disposed.

Now, to answer your question, the reader is using the same connection as the command you're trying to ExecuteNonQuery on. You need to use a separate connection since the DataReader keeps the connection open and reads data as you need it.

Josh M.
  • 26,437
  • 24
  • 119
  • 200
  • Nice save! ;-) Good for you. The second part wasn't there while I was writing the comment. Sorry. – David Mar 26 '11 at 03:27
  • Yeah I hit save prematurely you must have seen my answer during that 3 second window. – Josh M. Mar 26 '11 at 03:29
  • Im many cases, you really dont want to close the db connection every time. Normally, the db connection should remain open. And often you have a thread that polls the database for data, so one thread is doing that, but you also want other thread in the program to be able to SELECT or INSERT stuff, all on the same db connection... I usually use my own "wrapper" that wraps the connector, and then I dont have an open reader as I read all rows into memory. – Ted Nov 11 '13 at 09:55
  • This is interesting. For the last 10 years, we have opened a db connection (MySql), and kept it open, running all queries against that connection. I have never gotten this error, until now when I switched to OrmLite (ServiceStack). To me, it seems very strange that this behaviour exists: i want to open the connection once, and use it until the application closes. To open it every single time I want to do a query seems like a enormous overhead? – Ted Apr 26 '18 at 06:18
  • 1
    @Ted You are only _functionally_ "opening" and "closing" them. Technically, these calls merely borrow and return connections from the pool (assuming Pooling=True), which are kept open. This is managed by ADO.NET, Microsoft's underlying framework on top of which various connectors are built. This makes life much easier: if there is truly only one connection needed at a time, then the pool will likely only ever have a single connection. However, as soon as you start doing concurrent queries (e.g. writing while a reader is open), you will get multiple connections as needed. – Timo Sep 17 '18 at 10:29
37

Just use MultipleActiveResultSets=True in your connection string.

Shaiwal Tripathi
  • 497
  • 4
  • 16
27

Add MultipleActiveResultSets=true to the provider part of your connection string example in the file appsettings.json

"ConnectionStrings": {
"EmployeeDBConnection": "server=(localdb)\\MSSQLLocalDB;database=YourDatabasename;Trusted_Connection=true;MultipleActiveResultSets=true"}
user2321864
  • 2,207
  • 5
  • 25
  • 35
Chandan
  • 279
  • 3
  • 2
10

You are trying to to an Insert (with ExecuteNonQuery()) on a SQL connection that is used by this reader already:

while (myReader.Read())

Either read all the values in a list first, close the reader and then do the insert, or use a new SQL connection.

BrokenGlass
  • 158,293
  • 28
  • 286
  • 335
  • That's what I was going to put, but I was too busy commenting below. Darn it. Anyway, yeah, that's the answer - use a different connection object. +1 to you. – David Mar 26 '11 at 03:26
3

The issue you are running into is that you are starting up a second MySqlCommand while still reading back data with the DataReader. The MySQL connector only allows one concurrent query. You need to read the data into some structure, then close the reader, then process the data. Unfortunately you can't process the data as it is read if your processing involves further SQL queries.

Matthew Scharley
  • 127,823
  • 52
  • 194
  • 222
2

This exception also happens if you don't use transaction properly. In my case, I put transaction.Commit() right after command.ExecuteReaderAsync(), did not wait with the transaction commiting until reader.ReadAsync() was called. The proper order:

  1. Create transaction.
  2. Create reader.
  3. Read the data.
  4. Commit the transaction.
klenium
  • 2,468
  • 2
  • 24
  • 47
0

You have to close the reader on top of your else condition.

0

In my case, I was awaiting an async call, but in the calling scope, I was not awaiting that method that I was making the call in. So, the calling scope was continuing on while my connection was still open.

called scope:

protected override async Task AfterProcessing()
{
    var result = await Stats.WriteAsync();
    Log.Information("Stopping");
}

calling scope:

public virtual async Task Run()
{
    BeforeProcessing();
    try
    {
        Process();
    }
    finally
    {
        AfterProcessing(); // this line was missing an "await"
    }
}
0

There is another potential reason for this - missing await keyword.

kemsky
  • 14,727
  • 3
  • 32
  • 51
0

Set multipleactiveresultsets=true in your connectionstring

Multiple Active Result Sets (MARS) is a feature that allows the execution of multiple batches on a single connection. In previous versions, only one batch could be executed at a time against a single connection. Executing multiple batches with MARS does not imply simultaneous execution of operations.

Here's a Link

F.Rhman
  • 11
  • 7