I have a problem where it appears that the reader indicates that it has rows from the returned SQL but the while loop for the reader never runs. I put a messagebox in the reader.hasrows as a verification and I put a messagebox on the first line after the while loop as well. The messagebox for the hasrows is executed but the messagebox for the Read is not executed. It is very puzzling. I tried the query against the database and it indeed does return rows. Here is the code snippet.
using (DbConnection connection = CADBase.DbProviderFactory.CreateConnection())
{
connection.ConnectionString = CADBase.DbConnectionString;
connection.Open();
using (DbCommand command = connection.CreateCommand())
{
SQL = <statement here>;
command.CommandText = SQL
using (DbDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
//NEVER MAKES IT HERE
}
}
}
}
To future readers of this question: note that the problem occurred because the OP was returning too many columns in the query. See the comments below this answer.
I'm not quite sure why this is happening, but you really only need to check for rows once, not twice, and the Read() method already does this.
So all you really need is
while (reader.Read())
{
// Do your thing
}
call MoveNext() before first call to read
You should use reader.HasRows property and not the method.
Maybe you're getting an exception on reader.Read().
But since HasRows is a property and not a method. You need to write if(reader.HasRows) to make it compile.
if(reader.HasRows)
{
//MAKES IT HERE
while (reader.Read())
{
//NEVER MAKES IT HERE
}
}
So i'm wondering what the actual code is.
Just a guess. Maybe you are accessing the reader object in that messagebox shown after reader.HasRows and before reader.Read(). Apparently the Read() method returns true only if the reader has NOT reached the last row (see: https://stackoverflow.com/a/1540626/516481). So if the reader is at the last row it will return false! Maybe the query returns just one row and you change the internal state of the reader object somehow by accessing it (maybe using the debugger) and moving the reader to the last row?
Related
I have a Stored Procedure which sometimes return an exception after SELECT statement.
For example:
BEGIN TRY
SELECT
EmployeeId,
EmployeeName
FROM dbo.abc
THROW 50000, 'exception occurs here', 16;
END TRY
BEGIN CATCH
THROW 50000, 'exception', 16;
END CATCH
I am using ExecuteReaderAsync method to read data.
In case of exception, I should get exception in application. For example:
using (var reader = await ExecuteReaderAsync())
{
while (reader.Read())
{
}
}
But I am not getting any exception.
This is a very strange behaviour.
Because if this happens when we have some logic after SELECT and logic fails (e.g. any important UPDATE statement fails) then this will cause problem in the Application's behaviour.
Can somebody help me why I this strange behaviour is happening.
It is possible that this is simply because you disposed the reader before it had found the error - which is later in the stream than the first grid. Try doing:
using (var reader = await ExecuteReaderAsync())
{
while (reader.Read()) { ... }
// consume any trailing pieces
while (reader.NextResult()) {}
}
The second loop (over NextResult()) ensures that the TDS parser has consumed the entire result. You might also prefer to use await reader.ReadAsync() and await reader.NextResultAsync(), since you're clearly in an async method here.
I encountered this in an additional scenario using the following code:
using (DbDataReader reader = await command.ExecuteReaderAsync(CommandBehaviour.SingleResult).ConfigureAwait(false))
{
// ...
while (await reader.NextResultAsync().ConfigureAwait(false)) { }
}
In this scenario, CommandBehaviour.SingleResult will prevent the exception being raised when a result set is returned first, even when using the NextResult loop. It will stop reading from the connection once it receives a result which means it doesn't see the error.
To fix, just remove the CommandBehaviour parameter from ExecuteReaderAsync() and ensure you include the while loop.
I want to declare a MySqlDataReader, without initialising it or assigning any value to it. Like the code below.
MySqlDataReader rdr;
try
{ /* stuff to open the MySqlDataReader and use it, not important for my question */ }
catch (Exception e)
{ /* error handling stuff, not important for my question */ }
finally
{
/* code to close the reader when things have gone wrong */
try
{
if (rdr != null)
{
if (rdr.IsClosed == false)
{
rdr.Close();
}
}
}
catch (Exception e)
{ /* error handling stuff, not important for my question */ }
}
The reason for that is I want to close the MySqlDataReader in a finally section of the try if it does in fact I do get a run time error. So the MySqlDataReader has to be declared before of the try, otherwise it'll be out of scope for the finally code.
However when I compile the code above I get the compile time error "Use of unassigned local variable 'rdr'" so I want to set it to something for example
MySqlDataReader rdr = New MySqlDataReader();
But this give me a compile time error "The type 'MySql.Data.MySqlClient.MySqlDataReader' has no constructors defined". And assigning the result of a command object will make the code compile however that can go wrong and is what my try is trying to catch.
When this function is called for a second time if the MySqlDataReader object is not closed from the first iteration, then it will crash second time around.
So how do I clean up my MySqlDataReader objects when things go wrong?
Just assign it with null. The compiler will know a value has assigned, although it is null.
MySqlDataReader rdr = null;
In your finally block, check on the null value.
MySqlDataReader rdr = null;
try
{
... // do stuff here
}
finally
{
if (rdr != null)
{
// cleanup
}
}
Or use using if possible. It will cleanup rdr for you:
using (MySqlDataReader rdr = ... )
{
}
One option is to initialize it to null to start with:
MySqlDataReader rdr = null;
After all, you're already checking whether it's null within the finally block in your sample code, so that's fine.
It's not clear why you're not just using a using statement though. You can always put a try/catch inside (or outside) that.
I have a C#/WPF application with a tabbed interface that has been behaving strangely. After thinking originally my problems were related to the TabControl, I now believe that it's something different and I'm completely stuck. The following method is just supposed to pull some data out of the database and load a couple of WPF ComboBoxes. The strange thing is that the code reaches a certain point, specifically the end of the loop that loads cboState's Item collection, and then continues on. No code placed below that loop executes, no errors are thrown than I can find or see, and no breakpoints placed below that loop ever get reached. I'm completely perplexed.
private void loadNewProjectTab() {
dpDate.SelectedDate = DateTime.Now;
cboProjectType.Items.Add("Proposal");
cboProjectType.Items.Add("Pilot");
cboProjectType.SelectedIndex = -1;
string sql = "SELECT State FROM States ORDER BY ID";
OleDbCommand cmd = new OleDbCommand(sql, connection);
if(connection.State == ConnectionState.Closed) {
connection.Open();
}
OleDbDataReader reader = cmd.ExecuteReader();
while(reader.HasRows) {
reader.Read();
cboState.Items.Add(reader["State"].ToString().Trim());
} // <-- Nothing below here executes.
connection.Close();
}
while(reader.HasRows) {
reader.Read();
cboState.Items.Add(reader["State"].ToString().Trim());
}
reader.HasRows will return true even after you've read all the rows and moved past the last one with reader.Read(); at that point, you'll get an exception on reader["State"].
Since reader.Read() returns a boolean to indicate whether there's a current row, you should skip calling reader.HasRows entirely:
while(reader.Read()) {
cboState.Items.Add(reader["State"].ToString().Trim());
}
Um I think is wrong your loop it should be.
if (reader.HasRows)
{
while(reader.Read())
{
cboState.Items.Add(reader["State"].ToString().Trim());
}
}
Note that the bucle is with while(reader.Read())
This is your problem:
while(reader.HasRows) {
reader.Read();
cboState.Items.Add(reader["State"].ToString().Trim());
}
HasRows indicates whether or not the reader retrieved anything; it doesn't change as you read through it (in other words, it's not analogous to an end-of-file indicator like you're using it). Instead, you should do this:
while(reader.Read()) {
cboState.Items.Add(reader["State"].ToString().Trim());
}
Reader should be closed.
using(var reader = cmd.ExecuteReader())
{
if(reader.HasRows)
{
while(reader.Read())
{
cboState.Items.Add(reader["State"].ToString().Trim());
}
}
}
This is going to take some explaining. I'm new to ASP, having come from PHP. Completely different world. Using the MySql Connecter/Net library, I decided to make a database wrapper which had a fair amount of fetch methods, one being a "FetchColumn()" method which simply takes a string as its parameter and uses the following implementation:
public object FetchColumn(string query)
{
object result = 0;
MySqlCommand cmd = new MySqlCommand(query, this.connection);
bool hasRows = cmd.ExecuteReader().HasRows;
if (!hasRows)
{
return false;
}
MySqlDataReader reader = cmd.ExecuteReader();
int count = 0;
while(reader.HasRows)
{
result = reader.GetValue(count);
count++;
}
return result;
}� return result;
}public object FetchColumn(string query)
What I'm looking for is a way to return false IF and only IF the query attempts to fetch a result which doesn't exist. The problem is that, with my implementation, it throws an error/exception. I need this to "fail gracefully" at run time, so to speak. One thing I should mention is that with this implementation, the application throws an error as soon as the boolean "hasRows" is assigned. Why this is the case, I have no idea.
So, any ideas?
It's hard to say for sure, since you didn't post the exact exception that it's throwing, but I suspect the problem is that you're calling ExecuteReader on a command that is already in use. As the documentation says:
While the MySqlDataReader is in use, the associated MySqlConnection is busy serving the MySqlDataReader. While in this state, no other operations can be performed on the MySqlConnection other than closing it. This is the case until the MySqlDataReader.Close method of the MySqlDataReader is called.
You're calling cmd.ExecuteReader() to check to see if there are rows, and then you're calling ExecuteReader() again to get data from the rows. Not only does this not work because it violates the conditions set out above, it would be horribly inefficient if it did work, because it would require two trips to the database.
Following the example shown in the document I linked, I'd say what you want is something like:
public object FetchColumn(string query)
{
MySqlCommand cmd = new MySqlCommand(query, this.connection);
MySqlDataReader reader = cmd.ExecuteReader();
try
{
bool gotValue = false;
while (reader.Read())
{
// do whatever you're doing to return a value
gotValue = true;
}
if (gotValue)
{
// here, return whatever value you computed
}
else
{
return false;
}
}
finally
{
reader.Close();
}
}
I'm not sure what you're trying to compute with the HasRows and the count, etc., but this should get you pointed in the right direction.
you need to surround the error throwing code with a try clause
try {
//The error throwing Code
}
catch (exception e)
{
//Error was encountered
return false
}
If the error throwing code throws and error the catch statement will execute, if no error is thrown then the catch statement is ignored
First of all do a try and catch
try
{
//code
}
catch (Exception exp)
{
//show exp as message
}
And the possible reason of your error is that your mysql query has errors in it.
try executing your query directly in your mysql query browser and you'll get your answer.
If its working fine then double check your connection string if its correct.
NOTE:mark as answer if it solves your issue
Which of these methods is better for closing SqlDataReader:
SqlDataReader reader = comm.ExecuteReader();
while (reader.Read())
{
}
reader.Close();
reader.Dispose();
or
SqlDataReader reader = comm.ExecuteReader(CommandBehavior.CloseConnection);
while (reader.Read())
{
}
or there are another further closing methods?
The correct way of handling this is the using statement:
using(SqlDataReader reader = comm.ExecuteReader(CommandBehavior.CloseConnection)) {
while (reader.Read())
{
}
}
This way the object gets disposed correctly (and you don't need to call Close()).
A using statement is the best practice in such situations from my experience. It makes sure the connection is properly closed even if an exception happens somewhere inside.
using (SqlDataReader reader = comm.ExecuteReader())
{
while (reader.Read())
{
//Do stuff...
}
}
Of course you could do the same with a try { } finally { }, which is what the using statement does internally. I found it's generally a good idea to get in the habit of always handling readers via the using statement to avoid the possibility of leaked connections.
Use first scenario if you work with reader within one method and second one if you pass reader as return value (not within one scope).
the doc you need is this one: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.close.aspx
To quote: "You must explicitly call the Close method when you are through using the SqlDataReader to use the associated SqlConnection for any other purpose."