简体   繁体   中英

InvalidOpearationException: There is already an open DataReader

Hello I create controls from SQL via this code:

string query = "SELECT * FROM [schema] WHERE idSch=@id";
            SqlCommand com = new SqlCommand(query, con);
            com.Parameters.AddWithValue("@id", result);
            con.Open();
            SqlDataReader read= com.ExecuteReader();

            while (read.Read())
            {

                createLabelCmd((int)read["x"], (int)read["y"]);


            }
            con.Close();

The issue is that createLabelCmd contains SqlCommand and it needs an open SqlConnection

Inside createLabelCmd

String ResultSitting
private void createLabelCmd(int x, int y)
    {
for (int i = 0; i < 1; i++)
        {
            var newLabel = new Label();
            newLabel.Location = new Point(x, y);
            newLabel.Text = realpocsed.ToString();
            string sitting = newLabel.Name;
            string sittingSearch = (sitting).Substring(3, 1);
            if (sittingSearch != null && kzajezdu == "kZajezdu")
            {
                string querySitting = "SELECT name, surname FROM klient WHERE sitting = @sitting AND event=@event AND year=@year";
                SqlCommand cmdSitting = new SqlCommand(querySitting, spojeni);
                cmdSitting.Parameters.AddWithValue("@sitting", sittingSearch);
                cmdSitting.Parameters.AddWithValue("@event", idEvent);
                cmdSitting.Parameters.AddWithValue("@year", klientClass.Year());

                ResultSitting = cmdSitting.ExecuteScalar().ToString().Trim(); //This might be the issue

            }

            if (kzajezdu == "kZajezdu")
            {
                newLabel.MouseHover += delegate(object sender, EventArgs e)
                {
                    ToolTip ToolTip1 = new ToolTip();
                    ToolTip1.ShowAlways = true;
                    if (sittingSearch != null)
                    {
                        ToolTip1.Show(ResultSitting, newLabel);
                    }
                    else { ToolTip1.Show("This sitting is Empty!", newLabel); }
                };

            }

            panel1.Controls.Add(newLabel);
        }

I get an Exception: InvalidOpearationException: There is already an open DataReader associated with this Command which must be closed first.

May you please help me solve this out?

Edit as Soner Gönül suggested:

try
        {
            string query = "SELECT * FROM [schema] WHERE idSch=@id";
            SqlCommand com = new SqlCommand(query, con);
            com.Parameters.AddWithValue("@id", idSch);
            con.Open();
            SqlDataReader read= com.ExecuteReader();

            while (precti.Read())
            {
                createLabelCmd((int)read["x"], (int)read["y"]);

            }
            con.Close();
        }

Because when you while loop with your open SqlDataReader , there is an open connection already.

From DataReaders (ADO.NET)

“You can use the ADO.NET DataReader to retrieve a read-only, forward-only stream of data from a database.

Results are returned as the query executes, and are stored in the network buffer on the client until you request them using the Read method of the DataReader”

As a general recomendation, use using like;

using(SqlDataReader read= com.ExecuteReader())
{
    while (read.Read())
    {
       createLabelCmd((int)read["x"], (int)read["y"]);
    }
}

Or set this in your connection string;

...MultipleActiveResultSets=true;

The cause of the problem is outlined in other answers (while a DataReader is open, the connection used by that reader cannot serve other commands), however many fails to talk about MultipleActiveResultSets that has been introduced for this kind of situations

Just change your connection string to include this option and your code will work without any change

Server=yourServer;Database=yourDB;Trusted_Connection=True;MultipleActiveResultSets=true;

To complete the answer, MARS is available starting from SQL Server 2005 and there are minor problems that you should be aware of.

I guess you are writing a sitting planner and try to show labels at specific positions. Therefore, you would better select all records from klient table for a given event and put them in a DataSet . Then iterate through it (using a foreach ) and create the labels. This way, there is only ONE command that should be sent to database and , obviously, the performance of your application will be much better.

Having said that, I don't understand how your sittingSearch variable work and I think it needs revising.

You can either use a 2nd connection for createLabelCmd or turn on MARS (multiple active results sets) in your initial connection by adding "MultipleActiveResultSets=True" to your connection string.

http://msdn.microsoft.com/en-us/library/h32h3abf.aspx

Setting MARS to True AND making sure i used ToList(); in my if statements and returns in the below code i was missing the toList() in both conditions of the if statement, i was getting the error on IIS 8.5 after publishing .. updating the statement to the below worked@!

var varM = (id == 1) ? db.M.Where(x => x.UN== userID).ToList() : db.M.Where(x => x.EUN== userID).ToList();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM