Dynamics & Inherited Interfaces

A coworker and I made an interesting discovery today. I was getting a SQL error back indicating that a method–one that was clearly available to my object–wasn’t being found. We’d run into this issue before and found a work around, but it wasn’t until today that we dug in figured out why it was happening.

We’re using Dapper as our ORM. We use these statements all the time.

_db.Execute(“SELECT TOP 1 FROM dbo.MyTable”);
_db.Query("UPDATE dbo.MyTable SET MyField = 'new value'");

Many times we pass in data as such:

_db.Execute(“SELECT TOP 1 FROM dbo.MyTable WHERE Id = @id”, new {id = 5});

In this case, 5 would be some strongly typed object or variable. Dapper does great with these. We created a wrapper for Dapper that gives us some extra functionality:

public interface ICoolDb : IDapperDatabase
{
void WithTransaction(Action action);
}

The above is just an example of something you could do for wrapping up a bunch of SQL statements in a transaction. No biggie, right? This is also where the issue lies. I only have one method available here. If I try to pass in a dynamic object to Execute or Query, the compiler doesn’t evaluate the available methods until runtime. When it does evaluate, it doesn’t pick up the inherited interface methods of Execute or Query from IDapperDatabase, so it throws an error. For some reason, the compiler doesn’t know to work up the inheritance tree to find those methods. #fail

_db.Execute(“SELECT TOP 1 FROM dbo.MyTable WHERE Id = @id”, new {id = 5});

This works because id is strongly typed as int. The fix that we came up with awhile back was this:

_coolDb.Execute(sql, account as object);

This casts our dynamic account object as object which makes everyone happy. I’m not sure if this same quirk applies to later versions of .NET, but we’re running 4.5 and it’s there. It’s annoying to add that as object bit in there each time I’m passing a dynamic, but I guess it’s the best we can do.