Refactor code into using statement
-
05-09-2019 - |
Question
I have a dal layer with lots of methods, all of them call stored procedures, some return lists (so with a use of SqlDataReader
), others only a specific value.
I have a helper method that creates the SqlCommand
:
protected SqlCommand CreateSprocCommand(string name, bool includeReturn, SqlDbType returnType)
{
SqlConnection con = new SqlConnection(this.ConnectionString);
SqlCommand com = new SqlCommand(name, con);
com.CommandType = System.Data.CommandType.StoredProcedure;
if (includeReturn)
com.Parameters.Add("ReturnValue", returnType).Direction = ParameterDirection.ReturnValue;
return com;
}
Now my average (overly simplified) method body look like:
SqlCommand cmd = CreateSprocCommand("SomeSprocName"); //an override of the above mentioned method
try {
cmd.Connection.Open();
using (var reader = cmd.ExecuteReader()) {
//some code looping over the recors
}
//some more code to return whatever needs to be returned
}
finally {
cmd.Connection.Dispose();
}
Is there a way to refactor this, so that I won't lose my helper function (it does quite a bit of otherwise repetitive work), and yet be able to use using
?
Solution
One way is to change it from returning a command to taking a delegate which uses the command:
protected void ExecuteSproc(string name,
SqlDbType? returnType,
Action<SqlCommand> action)
{
using (SqlConnection con = new SqlConnection(this.ConnectionString))
using (SqlCommand com = new SqlCommand(name, con))
{
con.Open();
com.CommandType = System.Data.CommandType.StoredProcedure;
if (returnType != null)
{
com.Parameters.Add("ReturnValue", returnType.Value).Direction =
ParameterDirection.ReturnValue;
}
action(com);
}
}
(Note that I've also removed the includeReturn
parameter and made returnType
nullable instead. Just pass null
for "no return value".)
You'd use this with a lambda expression (or anonymous method):
ExecuteSproc("SomeName", SqlDbType.DateTime, cmd =>
{
// Do what you want with the command (cmd) here
});
That way the disposal is in the same place as the creation, and the caller just doesn't need to worry about it. I'm becoming quite a fan of this pattern - it's a lot cleaner now that we've got lambda expressions.
OTHER TIPS
You can do this:
protected static SqlCommand CreateSprocCommand(SqlConnection con, string name, bool includeReturn, SqlDbType returnType)
{
SqlCommand com = new SqlCommand(name, con);
com.CommandType = System.Data.CommandType.StoredProcedure;
if (includeReturn)
com.Parameters.Add("ReturnValue", returnType).Direction = ParameterDirection.ReturnValue;
return com;
}
and call it like this:
using (SqlConnection con = new SqlConnection(this.ConnectionString))
using (SqlCommand cmd = CreateSprocCommand(con, "SomeSprocName", true, SqlDbType.Int)
{
cmd.Connection.Open();
using (var reader = cmd.ExecuteReader())
{
//some code looping over the recors
}
//some more code to return whatever needs to be returned
}
You can nest using statements:
using (SqlCommand cmd = CreateSprocCommand("..."))
{
using (var connection = cmd.Connection)
{
connection.Open();
using (var reader = cmd.ExecuteReader())
{
...
}
...
}
}
How about:
using (SqlCommand cmd = CreateSprocCommand("whatever"))
{
cmd.Connection.Open();
using (var reader = cmd.ExecuteReader())
{
//blabla
}
}
Is this what you mean ?
using (SqlCommand cmd = CreateSprocCommand("SomeSprocName"))
{
cmd.Connection.Open();
using (var reader = cmd.ExecuteReader())
{
//some code looping over the recors
}
}