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.
Related
I am trying to save this to my datebase but I keep getting this error
System.InvalidOperationException
here is my code.
protected void btnSend_Click(object sender, EventArgs e)
{
con.Open();
cmd = new SqlCommand(#"INSERT INTO orders2
(orderName,orderFile,orderType,orderPrice,orderQuantity,orderShipped)
VALUES
('"+DropDownList1.SelectedValue+"','"+lblFile.Text+"','"+lblPrice.Text+"','"+txtQuantity.Text+"','"+DateTime.Now+"')",con);
cmd.ExecuteNonQuery();
con.Close();
lblFinished.Text = "Order has been submitted for process.";
}
WhoAmI is probably right, however your code could be greatly improved to avoid other problems and to also allow you not to allow unhandled exceptions.
I have put extra comments directly in the code:
try
{
// SqlConnection is disposable, so it is recommended to dispose it (using calls Dispose() for you)
using (var con = new SqlConnection(connStr))
{
con.Open();
// this is missing from your code and might the errors actual cause
// SqlCommand is also disposable
using (var cmd = con.CreateCommand())
{
// is is strongly recommended to construct parameterized commands
// to avoid SQL injection (check this - https://technet.microsoft.com/en-us/library/ms161953(v=sql.105).aspx)
cmd.Text = #"
INSERT INTO orders2
(orderName,orderFile,orderType,orderPrice,orderQuantity,orderShipped)
VALUES (#orderName, #orderFile, #orderType, #orderPrice, #orderQuantity, #orderShipped)";
// the parameters - SqlCommand infers parameter type for you
cmd.AddWithValue("#orderName", DropDownList1.SelectedValue);
cmd.AddWithValue("#orderFile", lblFile.Text);
cmd.AddWithValue("#orderType", theMissingParametersForOrderType);
// some conversion might be needed here, as I expect the price to be some number
// with a fixed number of decimals
// e.g. Convert.ToDecimal(lblPrice.Text)
cmd.AddWithValue("#orderPrice", lblPrice.Text);
// same convertion issue as for price
cmd.AddWithValue("#orderQuantity", txtQuantity.Text);
cmd.AddWithValue("#orderShipped", DateTime.Now);
}
}
}
// there are several Exceptions that can be raised and treated separately
// but this at least you can do
catch (Exception exc)
{
// log the error somewhere
// put a breakpoint just below to inspect the full error details
}
// this is executed even if an exception has occurred
finally
{
if (con != null && con.State != ConnectionState.Closed)
con.Close();
}
As a side note, this code belongs to a data layer, no presentation layer. Consider including it within another assembly.
You are inserting 6 values(orderName,orderFile,orderType,orderPrice,orderQuantity,orderShipped) here, but supplied only 5 values. DropDownList1.SelectedValue, lblFile.Text, lblPrice.Text, txtQuantity.Text, DateTime.Now.
Think about these 2 snippets:
Approach 1: use using statement
using(var connection = new SqlConnection())
using(var command = new SqlCommand(cmdText, connection)){
try{
connection.Open();
using(var reader = command.ExecuteReader(
CommandBehavior.CloseConnection | CommandBehavior.SingleResult){
while(reader.Read())
// read values
}
} catch (Exception ex) {
// log(ex);
}
}
Approach 2: use try/finally
var connection = new SqlConnection();
var command = new SqlCommand(cmdText, connection);
SqlDataReader = null;
try{
var reader = command.ExecuteReader(
CommandBehavior.CloseConnection | CommandBehavior.SingleResult);
while(reader.Read())
// read values...
} catch (Exception ex) {
// log(ex);
} finally {
command.Dispose();
if (reader != null) {
if (!reader.IsClosed)
reader.Close();
reader.Dispose();
}
if (connection.State != ConnectionState.Closed)
connection.Close();
connection.Dispose();
}
We all know that the using statements would be compiled to try/finally blocks. So is it correct to say: when the app get compiled, there would be 4 try blocks?
try { // for using SqlConnection
try { // for using SqlCommand
try { // my own try block
try { // for using SqlDataReader
} finally {
// dispose SqlDataReader
}
} catch {
// my own catch. can be used for log etc.
}
} finally {
// dispose SqlCommand
}
} finally {
// dispose SqlConnection
}
And, if the answer is yes, wouldn't that be a performance issue? Generally, is there any, I mean any performance difference between using blocks and try/finally blocks?
UPDATE:
From comments, I've to say:
1- The important question is, having multiple try blocks inside each other: is there any performance issue?
2- I have to care of code, because I'm responsible to code, not to query. The query-side has its own developer which is doing his best. So, I have to do my best too. So, it's important to me to take care of milliseconds ;) Thanks in advance.
Usually when you hear about try/catch is slow, it's all about exception handling. So if exception occurs then it might be slow. But just entering in try method is not something you should worry about. Especially in your case when you warp SQL query call.
If you want to know more about exceptions and performance in .NET you can find a lot of articles to read. For example: MSDN article or great CodeProject article.
And of course using is preferable way because it makes code much cleaner.
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
I have a C# database layer that with static read method that is called every second in background timer.
currently I create SqlCommand, SqlConnection once as a class memeber.
In every method call I execute the command to get the results,I am doing so to avoid creation of connection and command every second, but I am afraid from exception occurs in this method that will break the connection or put the object in the invalid state.
This is my current implementation (Timer Handler)
static void GetBarTime(object state)
{
lock (_staticConnection)
{
SqlDataReader dataReader = null;
try
{
dataReader = _getMaxTimeCommand.ExecuteReader();
dataReader.Read();
_currentTick = dataReader.GetInt32(0);
}
catch (Exception ex)
{
//Log the error
}
finally
{
dataReader.Dispose();
}
}
}
What is the best practise?
MORE DETAILS:
I am doing this in a timer as there is another prorcess update my table every second, and there is another exposed method used by set of clients and called every second to get the latest value.
So instead of executing select statement every second for each client, I am doing it in a timer and update global variable that is used by the clients.
SqlConnection has pooling built in; you would see almost no difference if you used:
using(SqlConnection conn = new SqlConnection(connectionString)) {
conn.Open();
// your code
}
each time. And that can react automatically to dead (underlying) connections.
Currently you have a bug, btw; if the command fails, the reader will still be null... either check for null before calling Dispose():
if(dataReader !=null) {dataReader.Dispose();}
or just use using:
try
{
using(SqlDataReader dataReader = _getMaxTimeCommand.ExecuteReader())
{
dataReader.Read();
_currentTick = dataReader.GetInt32(0);
}
}
catch (Exception ex)
{
//Log the error
}
It can be pretty difficult to find out if an execption means that the connection is a dead duck. To be on the safe side, you could close and reopen the SqlConnection and SqlCommand whenever you encounter an exception, just in case. That doesn't cause any overhead when everything works alright.