I've came across a code snippet like the following:
using (IDbCommand selectCommand = this.createCommand(selectSQL))
using (IDataReader theData = selectCommand.ExecuteReader())
{
while (theData.Read())
{
Phone aPhone = new Phone(...some code here...);
thePhones.Add(aPhone);
}
}
Now I am trying to learn the using statement in this context in by interpreting above code into old try/finally statement. From my understanding, the using statement will interpret the code after the brackets as try. In this case, try should enclose all the stuff after (IDbCommand selectCommand = this.createCommand(selectSQL)). However in this code, there is another using statement immediately comes after the first using.
Is it correct to interpret them as a nested try/finally statement in this context?
Using statements will automatically call Dispose() for any IDisposable object within it declaration. It's important to note that this is not a replacement for any try/catch/finally statements that your own code may need to do. The using statement ensures that Dispose() will be called if any code within it's block throws or not. This is extremely important any time I/O objects are used such as network calls, stream reading, database calls, etc. This will make sure you don't have memory leaks or locked files.
using (IDbCommand selectCommand = this.createCommand(selectSQL))
{
//an exception or not will call Dispose() on selectCommand
using (IDataReader theData = selectCommand.ExecuteReader())
{
//an exception or not will call Dispose() on theData
while (theData.Read())
{
Phone aPhone = new Phone(...some code here...);
thePhones.Add(aPhone);
}
}
}
The "equivalent" to running this code without using statements would be:
var selectCommand = this.createCommand(selectSQL);
try
{
var theData = selectCommand.ExecuteReader();
try
{
while (theData.Read())
{
Phone aPhone = new Phone(...some code here...);
thePhones.Add(aPhone);
}
}
finally
{
if (theData != null)
{
theData.Dispose();
}
}
}
finally
{
if (selectCommand != null)
{
selectCommand.Dispose();
}
}
However, the above code should not be used since the using statement is refined, optimized, guaranteed, etc, but the gist of it is above.
using (IDbCommand selectCommand = this.createCommand(selectSQL))
using (IDataReader theData = selectCommand.ExecuteReader())
{
}
At compile time will be converted to
using (IDbCommand selectCommand = this.createCommand(selectSQL))
{
using (IDataReader theData = selectCommand.ExecuteReader())
{
}
}
Just that. And it not related to try catch in anything
Yes, your code is interpreted as
using (IDbCommand selectCommand = this.createCommand(selectSQL))
{
using (IDataReader theData = selectCommand.ExecuteReader())
{
while (theData.Read())
{
Phone aPhone = new Phone(...some code here...);
thePhones.Add(aPhone);
}
}
}
which could be thought of as "nested try/finally blocks"
Using multiple using statements is just like with multiple if statements, you could do
if(foo)
if(bar)
{
DoStuff()
}
Which is the same as
if(foo)
{
if(bar)
{
DoStuff()
}
}
Related
This question already has answers here:
Why do we need Dispose() method on some object? Why doesn't the garbage collector do this work?
(2 answers)
What are the uses of "using" in C#?
(29 answers)
Closed 10 months ago.
I'm not talking about references to assemblies, rather the using statement within the code.
For example what is the difference between this:
using (DataReader dr = .... )
{
...stuff involving data reader...
}
and this:
{
DataReader dr = ...
...stuff involving data reader...
}
Surely the DataReader is cleaned up by the garbage collector when it goes out of scope anyway?
The point of a using statement is that the object you create with the statement is implicitly disposed at the end of the block. In your second code snippet, the data reader never gets closed. It's a way to ensure that disposable resources are not held onto any longer than required and will be released even if an exception is thrown. This:
using (var obj = new SomeDisposableType())
{
// use obj here.
}
is functionally equivalent to this:
var obj = new SomeDisposableType();
try
{
// use obj here.
}
finally
{
obj.Dispose();
}
You can use the same scope for multiple disposable objects like so:
using (var obj1 = new SomeDisposableType())
using (var obj2 = new SomeOtherDisposableType())
{
// use obj1 and obj2 here.
}
You only need to nest using blocks if you need to interleave other code, e.g.
var table = new DataTable();
using (var connection = new SqlConnection("connection string here"))
using (var command = new SqlCommand("SQL query here", connection))
{
connection.Open();
using (var reader = command.ExecuteReader()
{
table.Load(reader);
}
}
Such using statement automatically disposes the object obtained at the end of scope.
You may refer to this documentation for further details.
I have created a simplified SQL Data class, and a class method for returning a ready to use resultset:
public SQL_Data(string database) {
string ConnectionString = GetConnectionString(database);
cn = new SqlConnection(ConnectionString);
try {
cn.Open();
} catch (Exception e) {
Log.Write(e);
throw;
}
}
public SqlDataReader DBReader(string query) {
try {
using (SqlCommand cmd = new SqlCommand(query, this.cn)) {
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
} catch {
Log.Write("SQL Error with either Connection String:\n" + cn + " \nor Query:\n" + query);
throw;
}
}
(I catch any errors, log them, and then catch the error higher up the chain. Also, I did not include the ConnectionString() code for brevity. It just returns the requested connection string. That's all.)
This all works just fine, and with a single line of code, I'm ready to .Read() rows.
SqlDataReader rs = new SQL_Data("MyDatabase").DBReader(#"SELECT * FROM Employees");
while (rs.Read()) {
// code
}
rs.Close();
I want to expand this and add a .ColumnReader() method that I want to chain to .DBReader() like this:
string empID = new SQL_Data("MyDatabase").DBReader(#"SELECT * FROM Employees).ColumnReader("EmpID");
I attempted this by adding a .ColumnReader() method, but it ends up being a method of SQL_Data() class directly, not a member or extension of .DBReader(). I also tried adding the .ColumnReader() inside the .DBReader() (like a "closure"), but that didn't work either.
Can this be done?
This ended up working for me:
public static class SQLExtentions {
public static dynamic ColumnReader(this SqlDataReader rs, string colName) {
return rs[colName];
}
}
I will have to expand on it a bit to add some error checking, and perhaps return more than just the dynamic value - like return an object with the value and it's SQL data type. But Paul and Bagus' comments got me on the right track.
I'm trying to fetch data from DB with optional overload to pass the connection. I could do it in two ways.
public DataTable GetData()
{
using (SqlConnection con = new SqlConnection("..."))
{
return GetData(con);
}
}
public DataTable GetData(SqlConnection con)
{
// fetch data
return dtData;
}
or
public DataTable GetData(SqlConnection con=null)
{
bool OpenCon = false;
if (con == null)
{
con = new SqlConnection("...");
OpenCon = true;
}
try
{
// fetch data
}
finally
{
if (OpenCon)
con.Close();
}
return dtData;
}
The first case seems impressive. However, I am getting tons of methods for each transaction. In the second case, lots of code need to be written in each method as there is no way to use "using" block in this case.
The situation is still worse with other transactions like update or delete, since I need to have another overload to pass the transaction.
Is there a better way?
1st one is the best choice
public DataTable GetData()
{
using (SqlConnection con = new SqlConnection("..."))
{
return GetData(con);
}
}
public DataTable GetData(SqlConnection con)
{
// fetch data
return dtData;
}
Here you have Object oriented implementation, providing specific boundry as well as removal of object(using statement to destory objects ) are all there which is a good programmaing.
So in C#, I have an ODBCDataReader that returns that it has rows, but when I try to access the data it returns an object not set to a reference of an object error. I tested the sql directly on the db and it does return a row without any nulls
OdbcDataReader results;
try
{
// Initialize & open odbc connection
using (OdbcConnection conn = new OdbcConnection(connectionString.ToString()))
{
conn.Open();
// Initialiaze odbc command object
using (OdbcCommand comm = new OdbcCommand(query.ToString(), conn))
{
results = comm.ExecuteReader();
}
}
}
catch
{
//detailed error messaging here (which does not get hit)
}
temp = results;
if (temp.HasRows == false)
{
//error messaging here does not get hit.
}
while (temp.Read())
{
try
{
//I attempted to access the data by creating an object array:
object [] objarray = new object[temp.FieldCount)
temp.GetValues(objarray); //this causes error
}
catch{ // error is caught here "object not set to a reference of an object" }
for (i = 0; i < temp.FieldCount; i++)
{
try
{
//I also attempted other ways to access the data including:
temp[i].ToString(); // this causes error
temp.GetInt32(i).ToString(); // this causes error
temp.GetName(i); //this causes error
}
catch
{
// error is caught here "object not set to a reference of an object"
}
}
}
You are using it outside the using blocks. Move the part where you use [results] inside the using blocks (immediately after the ExecuteReader() call) and you should be in a much better place.
I ran into this same issue. The problem in my case was that I was not binding my parameters correctly. I was binding using #:
SELECT * FROM MyTable WHERE MyField = #MyField
For some reason, this is valid in MySQL and doesn't produce an error, but will not return data. The solution was to bind using ?:
SELECT * FROM MyTable WHERE MyField = ?
Then in C# bind the parameters:
cmd.Parameters.AddWithValue("#MyField", myFieldValue);
Old question, but it's the first result on Google and unanswered. Hope it's helpful.
I know what I asking might not make a lot of sense for C# experts but I'll explain what I want to do and then you can suggest me how to do it in a better way if you want ok?
I have a C# class called DatabaseManager that deals with different MySQL queries (ado.net NET connector, not linq or any kind of ActiveRecord-ish library).
I am doing something like
categories = db_manager.getCategories();
The list of categories is quite small (10 items) so I'd like to know what's the best way of accessing the retrieved information without a lot of additional code.
Right now I'm using a Struct to store the information but I'm sure there's a better way of doing this.
Here's my code:
public struct Category
{
public string name;
}
internal ArrayList getCategories()
{
ArrayList categories = new ArrayList();
MySqlDataReader reader;
Category category_info;
try
{
conn.Open();
reader = category_query.ExecuteReader();
while (reader.Read())
{
category_info = new Category();
category_info.name = reader["name"].ToString();
categories.Add(category_info);
}
reader.Close();
conn.Close();
}
catch (MySqlException e)
{
Console.WriteLine("ERROR " + e.ToString());
}
return categories;
}
Example:
public IEnumerable<Category> GetCategories()
{
using (var connection = new MySqlConnection("CONNECTION STRING"))
using (var command = new MySqlCommand("SELECT name FROM categories", connection))
{
connection.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
yield return new Category { name = reader.GetString(0) };
}
}
}
}
Remarks:
Let ADO.NET connection pooling do the right work for you (avoid storing connections in static fields, etc...)
Always make sure to properly dispose unmanaged resources (using "using" in C#)
Always return the lowest interface in the hierarchy from your public methods (in this case IEnumerable<Category>).
Leave the callers handle exceptions and logging. These are crosscutting concerns and should not be mixed with your DB access code.
The first thing I would do is to replace you use of ArrayList with List that will provide compile-time type checkig for your use of the category list (so you will not have to type cast it when using it in your code).
There's nothing wrong with returning them in an like this. However, a few things stand out:
Your catch block logs the error but
then returns either an empty array or
a partially populated array. This
probably isn't a good idea
If an exception is thrown in the try
block you won't close the connection
or dispose of the reader. Consider
the using() statement.
You should use the generic types
(List<>) instead of ArrayList.
From your code I guess you are using .NET 1.1, becuase you are not using the power of generics.
1) Using a struct that only contains a string is an overkill. Just create an arraylist of strings (or with generics a List )
2) When an exception occurs in your try block, you leave your connection and reader open... Use this instead:
try
{
conn.open();
//more code
}
catch (MySqlException e) { // code
}
finally {
conn.close()
if (reader != null)
reader.close();
}