Using Action<>, Func<> to hide using statements
Ok so to give you all some background. I always write my data access with a repository pattern in c#. Now I often use dapper, however I’d guess this problem would also apply with Entity framework.
Everytime I start writing my database access I always start with something like…
…and honestly pretty soon I am living in
using statement hell.
Now I tried to mitigate this in the past with IDisposable, but when I’d do some weak reference dependancy injection magic things usually got borked. I like to see using statements in action. I like know that things are getting disposed. However the verbosity, and sheer pain of it makes me want to puke. So one day I came up with the following.
Ok here is a basic example below using the Dapper orm.
So basically we create our db class passing in the type of database connection we wish to use in
<>. In this case we are using Sql server but in theory we could also use Postgres. We are making an annonymous function that gets passed x, which will be a database connection. This connection will already be created, with the proper connection string. We are then going to call dapper’s QueryAsync which will return an IEnumerable of
MyReturnType after calling MySproc. The Database connection will be disposed of without us having to worry.
var db = new DataBase<SqlConnection>("connectionstring");
Ok, so I know as a new c# programmer generics seem intimidating. So I will walk you through this.
You may have classes ask for a generic. This means they are asking for a class. Note the word class. This will not be an object.
First the line
public class DatabaseBase<T> where T : class, IDbConnection, new() declares that this class is public. This class is called DataBase. This class requires a generic which we will call T in this class. T will have to be a class (not interface, nor struct, or enum). This class must inhert from IDbConnection. This class can also be created without a constructor. Now Notice in my gist, where I am using my
using statements. You will see
new T() that is because we are newing the class we have passed as a generic.
Next up is a Func. Now Functions are a delegate, or method that when ran have a return type. Functions Must have a return. In this case the T is a passed in paramter. This means the delegate must be able to handle an IDbConnection somehow and return a TR.
In the following example we have a method declaration that takes in a function that has a result. This method also returns the result of the function (note the TR return type).
public TResult QueryDatabase<TResult>(Func<T, TResult> action)
Action<T> is essentially the same as
Func<T,TR> execpt actions do not have a return type. This would be more like a void than anything else. The T is a passed in parameter to the function. So you can pass in something like a database connection, but you will not have a return. Simple use case sql insert statement.