I have two questions.
1) Should you always use a using statement on a connection? So, I would use it on the connection and then another one on a reader within the connection? So I would be using two using statements.
2) Lets say you use the using statement on the connection and also a reader being returned on the connection. So you have two using statements. Does it create two Try{}Finally{} blocks or just one?
Thanks!
Be careful here. You should always have a using statement on any local object that implements IDisposable. That includes not only connections and readers, but also the command. But it can be tricky sometimes exactly where that using statement goes. If you're not careful it can cause problems. For example, in the code that follows the using statement will close your reader before you ever get to use it:
DataReader MyQuery()
{
string sql="some query";
using (var cn = new SqlConnection("connection string"))
using (var cmd = new SqlCommand(sql, cn))
{
cn.Open();
using (var rdr = cmd.ExecuteReader())
{
return rdr;
}
}
}
Instead, you have four options. One is to wait to create the using block until you call the function:
DataReader MyQuery()
{
string sql="some query";
using (var cn = new SqlConnection("connection string"))
using (var cmd = new SqlCommand(sql, cn))
{
cn.Open();
return cmd.ExecuteReader();
}
}
using (var rdr = MyQuery())
{
while (rdr.Read())
{
//...
}
}
Of course, you still have to careful with your connection there and it means remember to write a using block everywhere you use the function.
Option two is just process the query results in the method itself, but that breaks separation of your data layer from the rest of the program. A third option is for your MyQuery() function to accept an argument of type Action that you can call inside the while (rdr.Read()) loop, but that's just awkward.
I generally prefer option four: turn the data reader into an IEnumerable, like this:
IEnumerable<IDataRecord> MyQuery()
{
string sql="some query";
using (var cn = new SqlConnection("connection string"))
using (var cmd = new SqlCommand(sql, cn))
{
cn.Open();
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
yield return rdr;
}
}
}
Now everything will be closed correctly, and the code that handles it is all in one place. You also get a nice bonus: your query results will work well with any of the linq operators.
Finally, something new I'm playing with for the next time I get to build a completely new project that combines the IEnumerable with passing in a delegate argument:
//part of the data layer
private static IEnumerable<IDataRecord> Retrieve(string sql, Action<SqlParameterCollection> addParameters)
{
//DL.ConnectionString is a private static property in the data layer
// depending on the project needs, it can be implementing to read from a config file or elsewhere
using (var cn = new SqlConnection(DL.ConnectionString))
using (var cmd = new SqlCommand(sql, cn))
{
addParameters(cmd.Parameters);
cn.Open();
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
yield return rdr;
}
}
}
And then I'll use it within the data layer like this:
public IEnumerable<IDataRecord> GetFooChildrenByParentID(int ParentID)
{
//I could easily use a stored procedure name instead, and provide overloads for commandtypes.
return Retrieve(
"SELECT c.*
FROM [ParentTable] p
INNER JOIN [ChildTable] c ON c.ParentID = f.ID
WHERE f.ID= #ParentID", p =>
{
p.Add("#ParentID", SqlDbType.Int).Value = ParentID;
}
);
}
1) Should you always use a using
statement on a connection? So, I would
use it on the connection and then
another one on a reader within the
connection? So I would be using two
using statements.
Yes, because they implement IDisposable. And don't forget a using statement on the command too :
using (DbConnection connection = GetConnection())
using (DbCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT FOO, BAR FROM BAZ";
connection.Open();
using (DbDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
....
}
}
}
2) Lets say you use the using
statement on the connection and also a
reader being returned on the
connection. So you have two using
statements. Does it create two
Try{}Finally{} blocks or just one?
Each using statement will create its own try/finally block
You should always use a using statement when an object implements IDisposable. This includes connections.
It will create two nested try{}finally{} blocks.
Special point on 1). You need to specifically avoid that technique when the connection is used in asynchronous ADO.NET methods - like BeginExecuteReader, because more than likely, you will fall out of scope and try to dispose the connection while the async operation is still in progress. This is similar to the case when you are using class variables and not local variables. Often times the connection reference is stored in a class used as the "control block" for the asynchronous operation.
To answer each one:
1) Yes, this would be best practice to dispose both as soon as possible.
2) using() will create two blocks, wrapped in each other in the same order. It will dispose the inner object (the reader) first, then dispose the object from the outer using (the connection).
Probably this article will be interesting for you: How to Implement IDisposable and Finalizers: 3 Easy Rules
Related
I run a standard query against a DB2 database with C# ADO.NET OleDb and using statements and get
System.Data.OleDb.OleDbException (0x80004005): CLI0115E Invalid cursor state. SQLSTATE=24000
When I include the dispose methods for each OleDb object, the query runs.
Why does this fail without the Dispose methods? From everything i have researched the using statements should dispose of the objects for me. I am using .NET 4.5.1
using (OleDbConnection conn = DBConn.BIPSConn)
{
using (OleDbCommand cmd = new OleDbCommand(query, conn))
{
using (OleDbDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
string orderNumber = rdr.GetString(0).Trim();
string originCode = rdr.GetString(1).Trim();
string destinationCode = rdr.GetString(3).Trim();
Record record = new Record(orderNumber, originCode, destinationCode);
RecordList.Add(record);
}
// for unknown reasons, without these dispose methods we get an Invalid Cursor State error
rdr.Dispose();
}
cmd.Dispose();
}
conn.Dispose();
}
You have a using block -- you don't want to call Dispose() you want to call Close(). The using block will take care of the dispose. Add in a call to Close instead.
I have the following set of code:
using (OracleConnection conn = new OracleConnection(m_fceConn))
{
conn.Open();
using (OracleCommand cmd = new OracleCommand(m_sql, conn))
{
using (OracleDataReader reader = cmd.ExecuteReader())
{
reader.Read();
}
}
conn.Close();
}
Is there a better way to format this? Granted, later on I will probably be breaking out opening a connection, running a query, and closing the connection into separate functions at a later date but this nesting will still be there "behind the scenes" so to speak.
I read on another thread that I could format things like so:
using (OracleConnection conn = new OracleConnection(m_fceConn))
using (OracleCommand cmd = new OracleCommand(m_sql, conn))
But considering that I have code in between each of these statements I don't believe that I can omit the brackets like that. I'm just looking for the best/safest practice here since I'm still realtively new/noob to C#. Thanks.
I could be wrong, but I don't think you need to open the connection before passing it to OracleCommand. You just have to open it prior to executing a command. So you could write the above as:
using (OracleConnection conn = new OracleConnection(m_fceConn))
using (OracleCommand cmd = new OracleCommand(m_sql, conn))
{
conn.Open();
using (OracleDataReader reader = cmd.ExecuteReader())
{
reader.Read();
}
}
(you also shouldn't need to explicitly close either since disposing of the connection should close it automatically).
There's nothing special about the above code (other than it looks nice), it's just using normal C# rules that apply single commands to such blocks. it's the same as this:
if (...)
if (...)
dosomething(); // Look Ma, no curly braces
it's just that you're "stacking" multiple single statements.
What you have is properly formatted, though it's not necessary to call conn.Close() since the connection will be disposed (and thus closed) at the end of the using block that declared it.
You can, however, omit the brackets for the second statement, since the entirety of that statement is just another using block.
Your first using statement needs to have brackets, since you have the conn.Open() call there. The second and third can be stacked as you stated, which is pretty idiomatic C# (and preferred, in my case).
using (OracleConnection conn = new OracleConnection(m_fceConn))
{
conn.Open();
using (OracleDataReader reader = new OracleCommand(m_sql, conn).ExecuteReader())
{
reader.Read();
}
conn.Close();
}
EDIT
On second thought, don't do this. It wouldn't dispose of the command object. I will leave the answer here as an example of what NOT to do.
If I want to run multiple SELECT queries on different tables, can I use the same SqlDataReader and SqlConnection for all of them?? Would the following be wise?? (I typed this up fast, so it lacks try/catch):
MySqlCommand myCommand = new MySqlCommand("SELECT * FROM table1", myConnection);
myConnection.Open();
SqlDataReader myDataReader = myCommand.ExecuteReader();
while(myReader.Read())
{
//Perform work.
}
myCommand.commandText = "SELECT * FROM table2";
myReader = myCommand.ExecuteReader();
while(myReader.Read())
{
//Perform more work
}
myReader.Close();
myConnection.Close();
Thanks a lot.
You can use the same connection for each of them, as long as you do not try to execute multiple queries concurrently on the same connection from different threads.
As for the data reader, you are not actually re-using the reader, each call to ExecuteReader returns a new instance of a new reader, all you are re-using is the variable that maintains the reference to the reader. Here in lies a problem, you are only explicitly closing the last reader and leaving the first to be GC'd at some later time.
You can reuse the Command as well, but remember if you supply parameters etc. you will need to clear them for the next query unless they apply to the next query as well.
You should use try/finally blocks to ensure that you clean up the resources, or here is a quick change to your code to use using statements to ensure resource clean-up even if there is an exception that prevents the rest of the code from executing.
using (var myConnection = GetTheConnection())
{
myConnection.Open();
var myCommand = new MySqlCommand("SELECT * FROM table1", myConnection))
using (var myDataReader = myCommand.ExecuteReader())
{
while(myReader.Read())
{
//Perform work.
}
} // Reader will be Disposed/Closed here
myCommand.commandText = "SELECT * FROM table2";
using (var myReader = myCommand.ExecuteReader())
{
while(myReader.Read())
{
//Perform more work
}
} // Reader will be Disposed/Closed here
} // Connection will be Disposed/Closed here
Note: GetTheConnection is just a place holder function for what ever mechanism you are using to get your connection instance.
I generally use Adapters so I am rusty on the details of the reader, but I think you are on the right track.
One item of note in your code is that each call to ExecuteReader should be generating a new data reader. You may be reusing the variable name, but the reference to the existing reader is discarded and replaced by a new one on each call. Point being, close the previous reader before using ExecuteReader to get a new one.
How can I improve this method so that it works with multiple tables?
public void ExecuteStoredProcedure(string StoredProcedureName)
{
using (var connection = new SqlConnection(provider.ConnectionString))
{
using (var command = new SqlCommand(StoredProcedureName, connection))
{
command.CommandType = System.Data.CommandType.StoredProcedure;
using (var reader = command.ExecuteReader())
{
while (reader.Read())//problem is here
{
Console.WriteLine(reader[0].ToString());
}
}
}
}
}
I could return the reader (but I think that means I'd have to drop my using statements). Or, I could create a factory that processes each table depending on a parameter that I add to the ExecuteStoredProcedure(). Or whatever.
How can I get the reader functionality outta here?
Use SqlDataReader.NextResult. Have a look at article - How To Handle Multiple Results by Using the DataReader in Visual C# .NET
I'm a big fan of keeping my code simple and trim so it can be re-usable, on thing i'm struggling with is using the data reader for different types of objects, I had it in a method and found there were problems with connections closed or being left open. SO I am being forced, for the mean time to copy and paste the code, which is something I hate!!!
Is there any way I can scale this down so I can put it in a method and make it re-usable and nice?
ENT_AuctionBid ret = new ENT_AuctionBid();
try
{
SqlParameter[] Params = new SqlParameter[]{
new SqlParameter("#ID", ID )
};
using (SqlConnection conn = new SqlConnection(this.ConnectionString))
{
using (SqlCommand command = new SqlCommand("GetItem", conn))
{
SqlDataReader reader;
command.CommandType = CommandType.StoredProcedure;
conn.Open();
command.Parameters.AddRange(Params);
reader = command.ExecuteReader(CommandBehavior.SingleRow);
while (reader.HasRows)
{
while (reader.Read())
{
//
ret = this.Convert(reader);
}
reader.NextResult();
}
reader.Close();
}
}
}
catch (Exception ex)
{
}
return ret;
You should use SQLDataAdapter.
Here's a nice example on how to use it:
http://www.dotnetperls.com/sqldataadapter
Also, you might want to consider switching to Entity Framework, it will make your data access much, much easier, but might be complicated in an existing project.
You can make it using a lot less lines:
// Skipped creating temp variable
try {
using (SqlConnection conn = new SqlConnection(this.ConnectionString))
using (SqlCommand command = new SqlCommand("GetItem", conn) { CommandType = CommandType.StoredProcedure} ) {
command.Parameters.AddWithValue(#ID, ID);
conn.Open();
// reader is IDisposable, you can use using
using (var reader = command.ExecuteReader(CommandBehavior.SingleRow)) {
// Skipped parsing multiple result sets, you return after the first
// otherwise there's no point using SingleRow
// If nothing is read, return default value
return reader.Read() ? this.Convert(reader) : new ENT_AuctionBid();
}
}
}
catch (Exception ex) {
// Handle your exception here
}
// Return default value for error
return new ENT_AuctionBid();
All connections are closed using this code (because using is used). No unneeded loops are created, becuase you only expect a single row. And the temporary variable is not needed, so the abondend object is not created, only when it is used it is created.
This is a bit smaller:-
try
{
using (SqlConnection conn = new SqlConnection(this.ConnectionString))
{
using (SqlCommand command = new SqlCommand("GetItem", conn))
{
command.Paramaters.AddWithValue("#ID",ID);
command.CommandType = CommandType.StoredProcedure;
conn.Open();
reader = command.ExecuteReader();
while (reader.Read())
{
//
ret = this.Convert(reader);
}
}
}
}
catch (Exception ex)
{
}
Create helper methods for creating and returning an object of type SqlCommand. Pass a connection object to this helper method as well as stored procedure name and parameters list (if any). If you have different objects that are created from the data reader, pass the data reader to a constructor and let it generate an object based on that data.
As for closing the connection you should always have try...catch...finally. In the finally section close the connection.
In my projects i usually solve this problem creating an utility class that contains all the methods to access to the DB and manage inside all the stuff related to the db connection and the adapter.
For example a class called DBSql which contains a connection (SqlConnection connection;) as private member and the following methods:
//execute the query passed to the function
public System.Data.DataSet ExecuteQuery(string query)
//returns if a query returns rows or not
public bool HasRows(string query)
//execute commands like update/insert/etc...
public int ExcuteNonQuery(string sql)
In my class, you just pass a string and the class initialize the various DataAdapter and Command to execute it and return a dataset. Obiously you can complicate it to manage parameters/transaction and everything else.
In this way you are sure that the connection and the object are always handled the same way, and, hopefully, in a correct way.
You can use a utility file, such as SqlHelper.cs from Microsoft Data Access Application Block. Then all the code you need is this:
using (SqlDataReader sdr = SqlHelper.ExecuteReader(this.ConnectionString, "GetItem", ID))
{
while (sdr.Read())
{
ret = this .Convert(sdr);
}
}
You could start using LINQ-to-SQL, which has it's own DataClass system in which you just drag-&-drop your database tables and stored procedures. Then you just have to create an instance at the top of your classes -- private MyCustomDataClass _db = new MyCustomDataClass(); and then you can just type in _db.<Here all datatables and SPROCs will appaer for you to choose>.
Example (from when all SPROCs are added to the DataClass)
private MyCustomDataClass _db = new MyCustomDataClass();
public void MethodToRunSPROC(string email, Guid userId)
{
_db.MySPORC_AddEmailToUser(email, userId);
}