Dev: A Dapper Wrapper, deferred async

As a company based around a software solution, not only do we want to contribute ideas around social services, but we want to contribute to the world of software. This is part of a series of posts about some things we are doing without code.

Travis Marble
Pulse For Good
3 min readApr 6, 2020

--

There is a good chance one of the following two things is true:

  1. There is a better way to do this, if so (please add to the conversation)
  2. Dapper may already do this, and I am just oblivious.

One thing, however, is true; I learned a lot in trying to do this.

If you are used to Microsoft’s Entity Framework and Async Await, you will recognize this pattern:

I appreciate this syntax because I can do my await last, I also get to defer execution of the database query till I am ready to process the data.

With Dapper, I found myself doing this a lot:

While not terrible, it wasn’t as fluid to write as the EF statement above.

So, I decided to write an IDapper wrapper that lets me do this:

Additionally, if you wanted to chain another select, you can as follows:

A quick note: I used extension methods to accomplish this. I have a love/hate relationship with extension methods. I think they are cool and awesome to use, but I do worry about the effect they have on code dependency discovery and testing. But that’s a rant for another day.

To accomplish the above I wrote the following interface:

My extension method looked something like this:

The function create takes two Func arguments, one that returns an IEnumerable (for the non-async path) and Task<IEnumerable> for the async path. These Func variables are stored on the IDapper object.

So, how do we chain in a select and still defer execution till .ToList() or .ToListAsync()? I wrote an implementation of Select that creates a new IDapper object chaining a select onto the invoked Func from above. At this point no Funcs have been invoked, as we just create a new Func here.

So we now have a Func with a call to our initial Func inside it. While dapper doesn’t have the option to pass a cancellation token, I allowed for one to be passed in. One, I wanted to prove to myself I could do it, two, maybe it will be beneficial in the future, three, I may remove it because its confusing to expect cancellation but not actually get it from Dapper.

My implementation of ToList and ToListAsync:

In our example above, with a select, calling ToList or more importantly ToListAsync finally invokes our Func (this is the one we got from the Select), which in turn invokes the one from the original IDapper, executing the query against the database.

I also implemented the IEnumerable interface, I haven’t played much with that, but figured it would be nice to have.

Any feedback? I don’t necessarily think this is the one and only way to do this, or possibly the right way (please contribute to the conversation if there are better ways of doing this). But I do like the way it cleaned up my calling code and moved the await to a more convenient place of code.

--

--