Hooking Into Entity Framework With EFHooks
Coming from working with Rails, there are things that I miss when using .NET (as exhibited by my last post). Today I’m going to tell you about a way to bring a bit of Active Record to Entity Framework.
When using Active Record, you can hook into the process at various points to perform actions. Let’s say you want to do something before a model is created, like set a date for audit purposes.
ASIDE: Audit columns of
created_at
andupdated_at
are automatically handled by Active Record (by default). I wish this sort of functionality existed in Entity Framework, but we’ll be able to do just that if you keep reading!
Here’s a simple Rails example of hooking into the before_create
callback (This example is from the Rails docs)
Now, if there was only a way to do the same thing with Entity Framework… ;)
NOTE: You can, of course, implement your own “hooks” in Entity Framework by overriding the SaveChanges
method, but that gets messy.
Introducing EFHooks
In my quest to find something similar to Active Record’s callbacks, I stumbled upon the EFHooks project. This project is simply awesome! Instead of messing with overriding SaveChanges
, I’m able to inject various bits of code into the save process (e.g. Pre/Post, Insert/Update/Delete hooks). Let’s take that Active Record example from above and see how we’d accomplish the same thing using Entity Framework.
Easy Hooking
Let’s start with a PreInsertHook
. Creating a hook is just a simple class, which inherits from the EFHook class (PreInsertHook
in our case), then just override the Hook
method.
The EFHook classes are generic, so they will take in any object type. You can use an interface (like ITimeStamped
in the example above) or a specific class (e.g. Post
or User
).
What we’ve said here is: “Anytime there is an insert of an object that implements ITimeStamped
, set the CreatedAt
property to the current data/time.”
All we need to do is simply call SaveChanges()
on our context.
That’s the hook, but we need to tweak our DbContext
class to tell it to use the hook. Simply derive your DbContext from the EFHooks.HookedDbContext and register the hooks.
Once your context inherits from HookedDbContext
, your SaveChanges
calls are enhanced to call any hooks that you have registered.
EFHooks vs. VisoftInc.EFHooks
What are you waiting for? Head over to NuGet and grab the EFHooks package… Whoops, wait! There are two different packages. EFHooks and VisoftInc.EFHooks. What’s going on here?
The EFHooks project was started by Kevin McKelvin. Back in 2011, I submitted a pull request, but sadly, a new NuGet package was never published. As of today, the latest official version of EFHooks was published on 2011-09-18, and is v1.0.2.
I wanted to use EFHooks in multiple projects, and that is what spurred me to create a new NuGet package, VisoftInc.EFHooks.
Since that first change where I added the ability to use the existing context within a hook, I’ve also changed EFHooks to support stub entities (e.g to build relationships without loading objects in an MVC app). Just recently, I added .NET 4/4.5 support and changed the Entity Framework base version to 5.0.0. All of these changes have been published to the VisoftInc.EFHooks package. I’ve made these changes while using EFHooks in multiple projects. These changes have made a big difference, especially working within a .NET 4.5 project where the version of Entity Framework 5 differs between .NET 4 and 4.5.
I would be happy to push all my changes to the main EFHooks branch if Kevin will still actively maintain the project and publish changes to NuGet, but alas, for now, I use (and would recommend) the VisoftInc.EFHooks package. If you find any issues with VisoftInc.EFHooks, let me know on GitHub, or better yet, send me a pull request!