C# reader is closed while reading? - c#

I am running a C# windows application, and I get an error message when trying to use a datareader. The error message is:
"Invalid attempt to call CheckDataIsReady when reader is closed."
I used stop point and saw that the code works fine until it enters the "while" loop. Once inside, it gives the error message.
I have tried to do it without closing the previous reader, but then the message changed to something like "there is already an open reader" or some such.
Here's the code:
conn = new SqlConnection(DBConnectionString);
SqlCommand select_cmd = new SqlCommand("SELECT usrRealname, usrIsowner FROM tblUSERS WHERE usrNum = " + UserID, conn);
SqlCommand select_orders = new SqlCommand("SELECT orderNum, orderBy, orderShipadrs, orderDate, orderTotal FROM tblOrders WHERE orderDeliveryDate is NULL AND fkorderTakenbyusrnum = " + UserID, conn);
conn.Open();
SqlDataReader dr = select_cmd.ExecuteReader();
dr.Read();
CurrentUser User = new CurrentUser(Convert.ToString(dr[0]), UserID, Convert.ToBoolean(dr[1]));
DetailsLabel.Text = String.Format("Welcome {0}, ID number {1}. {2}", User.getname, UserID, User.getOwner);
dr.Close();
SqlDataReader orders = select_orders.ExecuteReader();
while (orders.Read())
{
UnfulfilledOrders CurrentOrder = new UnfulfilledOrders(Convert.ToInt32(dr[0]), Convert.ToString(dr[1]), Convert.ToString(dr[2]), Convert.ToString(dr[3]), Convert.ToInt32(dr[4]));
OrderList.Items.Add(CurrentOrder);
}
What I'd trying to do is add class (UnfulfilledOrders) type objects to a listbox (OrderList).
The thing that baffles me is that I used such a while loop in a previous form in the same app, and it worked fine there.
I really have no idea what I'm doing wrong.
I tried twiking the code, adding or removing certain parts, but nothing seems to work.

Your problem is that in your while loop you're using dr[0] instead of orders[0]. This is trying to get the value from the SqlDataReader dr.
A good way to avoid mix-ups like this would be to create the data reader in a using block.
using (var dr = select_cmd.ExecuteReader())
{
//your code here
dr.Close();
}
then
using (var orders = select_orders.ExecuteReader())
{
// your code here
orders.Close();
}
This would prevent you from accidently referencing the wrong reader because VS would give you an error saying it doesn't exist.

Your code:
dr.Close(); //<-- dr closed
SqlDataReader orders = select_orders.ExecuteReader(); // <-- Reader is "orders" here
while (orders.Read())
{
UnfulfilledOrders CurrentOrder = new UnfulfilledOrders(Convert.ToInt32(dr[0]), Convert.ToString(dr[1]), Convert.ToString(dr[2]), Convert.ToString(dr[3]), Convert.ToInt32(dr[4]));
OrderList.Items.Add(CurrentOrder);
}
dr was closed previously, do you mean "orders" instead of "dr"?

Related

MySqlDataReader object not receiving any data from function

I have a post action method which takes in a username and password from a form. In this action method I am using a function to execute a mysql command to a database
This is the function to read from the database
public static MySqlDataReader GetDataFromDB(string command)
{
using (MySqlConnection con = new MySqlConnection(ConStr))
{
com = new MySqlCommand(command, con);
con.Open();
MySqlDataReader rdr1 = com.ExecuteReader();
while (rdr1.Read())
{
}
return rdr1;
}
}
This is how i tried to use this function in my action method
MySqlDataReader rdr2 = Helper.GetDataFromDB("select * from library.Accounts where username = '" + username + "' and password = '" + password + "'");
I put a breakpoint in the helper method and could see that it was reading from the database fine with it storing all the expected row data in the internal 'rdr1' object however it isnt returning anything at the end as the 'rdr2' object is empty once it's finished. I don't know if something is wrong or if im just being an idiot and so i would appretiate if anyone can tell me where im going wrong.
A Data Reader such as MySqlDataReader is Forward Only. This means that once the data has been read and moved on to the next record, or the end of the data, it cannot go back to the beginning.
If you remove this block of code:
while (rdr1.Read())
{
}
You should find it will return the Data Reader at the start, and therefore be able to read the data you loaded from the database.
In addition, you should know that when the using () {...} block finishes the connection will be closed, along with the Data Readers ability to read the data.
If you do want to return the Data Reader, remove the using() {...} block to be a simple statement like:
MySqlConnection con = new MySqlConnection(ConStr);
If you do want to navigate backwards and forwards, filter or sort the data after it has been loaded, you should LOAD the data in to a DataTable from the Data Reader.
Example:
DataTable dt = new DataTable();
dt.Load(rdr1);

"Connection must be valid and open" - DataReader problem

I'm trying to take from a DataBase all under aged users, but when I try to, System.InvalidOperationException: 'Connection must be valid and open.'
pops up. It's a Windows Form app, so this happens when I press the button.
I have tried searching for the problem but I cant find the error. I have 5 more functions with the same syntax and they work just fine. This is the code I have:
public static List<User> Underage(MySqlConnection connection)
{
string query= string.Format("SELECT * FROM users WHERE age<18");
MySqlCommand command = new MySqlCommand(query, connection);
MySqlDataReader reader = command.ExecuteReader();
List<User> underage= new List<User>();
if (reader.HasRows)
{
User usu = new User();
while (reader.Read())
{
usu.id = reader.GetInt16(0);
usu.name = reader.GetString(1);
usu.surname= reader.GetString(2);
usu.email = reader.GetString(3);
usu.age= reader.GetInt16(4);
usu.birth = reader.GetDateTime(5);
usu.payment= reader.GetFloat(6);
underage.Add(usu);
}
}
return underage;
}
Thanks anyways and sorry if it's a stupid problem, but I just cant figure it out.
Thanks for clarifying my problem mjwills and Adyson, you were right, I forgot to open it. I have a function to open the connection which I used in every other method of my program but I forgot to add it in this one. Sorry and thank you!

Close SqlDataReader if there are no more rows left to read - C#

This is causing me a headache. I know this question (or atleast variants of it) has been asked many times but before one flags it as a duplicate please consider the following code:
string myConnectionString = myConnectionString = ConfigurationManager.ConnectionStrings["DBCS"].ToString();
SqlConnection mySQLConnection;
SqlCommand mySQLCommand;
SqlDataReader mySQLDataReader;
using (mySQLConnection = new SqlConnection(myConnectionString))
{
mySQLCommand = new SqlCommand("SELECT TOP 1 * FROM Table ORDER BY Id DESC", mySQLConnection);
mySQLCommand.Connection = mySQLConnection;
mySQLCommand.Connection.Open();
using(mySQLDataReader = mySQLCommand.ExecuteReader())
{
if (mySQLDataReader.HasRows)
{
if (mySQLConnection.State == ConnectionState.Open)
{
while (mySQLDataReader.Read())
{
//Perform Logic : If the last record being returned meets some condition then call the below method
MethodCalled();
}
}
}
}
MessageBox.Show("Connection state: " + mySQLConnection.State);
}
I would like to find a way to either:
Close the reader after it has finished reading
Break out of the while-loop when it has finished reading and there are no more rows left
But I just keep on getting a SqlException stating the following:
invalid attempt to call read when reader is closed
Just from broad observation, I can trace that error is due to me returning data that contains one row only. The problem is that after it has read that row, the compiler goes back to While(mySQLDataReader.Read()){} and attempts to read through a table that does not contain any rows.
I attempted the following:
Wrapping the ExecuteReader() from the command object in a using block so that it automatically closes the reader and the connection respectively once it has done reading like so:
using(mySQLDataReader = mySQLCommand.ExecuteReader())
{
//Logic performed
}
Just before the closing brace of the while-loop, I tried checking if there are any more rows left/returned from the sql command and breaking out the loop once that condition is satisfied:
if(mySQLDataReader.HasRows == false) //No more rows left to read
{
break; //break out of loop
}
Both attempts were unsuccessful. How can I get around this?
It must be one of the following 3 things:
You're using Read() OUTSIDE the using block. Remember that using block will implicitly call Close and Dispose on your reader. Thus any Read() calls must be placed inside the using block.
The body of your using block is explicitly closing the reader. This seems improbable.
Apparently you have declared your mySQLDataReader at a higher level. It could be that some other (async) code is closing the reader. This also is unlikely. You shouldn't, in most cases, define a DataReader at global level.
Edit
Reading the full code block that you have posted now, I'd suggest a few changes. Can you run the following and tell us if it runs:
using (var mySQLConnection = new SqlConnection(myConnectionString))
{
mySQLCommand = new SqlCommand("SELECT TOP 1 * FROM Table ORDER BY Id DESC", mySQLConnection, mySQLConnection);
mySQLCommand.Connection.Open();
using(mySQLDataReader = mySQLCommand.ExecuteReader())
{
while (mySQLDataReader.Read())
{
//Perform Logic : If the last record being returned meets some condition then call the below method
MethodCalled();
}
}
}
If this version runs fine, we can then dig the problem better.
If there is no data to iterate, while loop will not execute at all. Do you need to check for HasRows as such? Also, you should use CommandBehavior.CloseConnection when you are creating data reader. This will make sure that underlying connection is closed once you have read through it.
Should if call SqlDataReader.HasRows if I am calling SqlReader.Read
SQLDataReader Source Code
using (SqlConnection mySQLConnection = new SqlConnection(myConnectionString))
{
using (SqlCommand mySQLCommand = new SqlCommand("SELECT TOP 1 * FROM Table ORDER BY Id DESC", mySQLConnection))
{
mySQLConnection.Open();
SqlDataReader mySQLDataReader = mySQLCommand.ExecuteReader(CommandBehavior.CloseConnection);
while (mySQLDataReader.Read())
{
//Code logic here
}
// this call to mySQLDataReader.Close(); will close the underlying connection
mySQLDataReader.Close();
}
MessageBox.Show("Connection state: " + mySQLConnection.State);
}

Npgsql C# throwing Operation is not valid due to the current state of the object suddenly

I have a C# winform application and everything was working fine, but after prolonged use of the app I started getting this error
Operation is not valid due to the current state of the object
The error is from a function that executes every 5 seconds to get a list of names from the database
NpgsqlCommand cmd = new NpgsqlCommand(
String.Format("select pid,name from queue order by id"), conn);
NpgsqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
queue[(int)reader["pid"]] = (string)reader["name"];
}
This list contains names in a queue and needs to be updated in as short time as possible
From what I have read, it seems like a new limitation from .net framework..
Any better way to do this or a workaround to avoid this error?
Edit: and btw, I dont understand the limitation! I added a function that enters more than 100000 entries into the database and I didn't get this error!
Do you dispose reader and cmd after use? This could be memory leak-related where the postgres-provider ends up running out of an internal resource after some time.
You should follow a using-pattern like described on their homepage: http://www.npgsql.org/doc/
using (NpgsqlCommand cmd = new NpgsqlCommand(
String.Format("select pid,name from queue order by id"), conn))
{
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
queue[(int)reader["pid"]] = (string)reader["name"];
}
}
}

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

Categories