Entity Framework is a powerful tool with so many features it's hard to know them all. I am constantly getting surprised by just how smart it can be. Sometimes you might want it to do just a little bit more.
Unfortunately, there is no real documentation about how to add functionality to Entity Framework. What's there is usually either outdated or not that helpful. I want to emphasize here that I am not putting any blame on the EF team - they have been making huge strides with each release of EF Core. And the regular docs are being updated. With all that, it's not surprising that there is no time to document intricate details that very few people will see.
That does not mean there is no information about how to approach this. This is the Internet, after all. I wanted to highlight some places that helped me while developing the auditing solution described in a previous post.
The resource that has the most information is, naturally, the EF Core repository:
There's a lot of information that can be found in the reported issues. What's more, the code itself is usually pretty easy to follow, even if you haven't seen it before.
Another great place is this StackOverflow answer:
I found it after looking pouring through the EF Core sources and stitching together a mental image of how it's all connected. Of course, all this time it was already figured out and explained on SO.
Last but not least, if you're planning on customising Entity Framework, make sure to check out the
It's very impressive and helped me understand the internals of EF Core better than I had before. Even though my project took a slightly different route, it's still an amazing project.
Even though there's a lot of information at the links above, I believe I still have some tricks worth sharing.
Design Time Services
There are some services that EF uses only at design time (think migration scaffolding etc.). There's a complete list of them at List of services. A good example of those services are implementations of
ICSharpMigrationOperationGenerator, which are responsible for generating the code that's placed in the migration
Replacing the services with your own implementations is comically easy. The only thing that needs to be done is to implement the
Entity Framework will use
magic reflection to find the implementation and execute the
ConfigureDesignTimeServices method. Cool.
BUT, if you look at the code doing just that in the
You will notice that only the startup assembly is scanned. That's very unfortunate if you plan of releasing your extensions as a library or even if you just wanted to isolate all that EF-specific code in a separate project.
However, if you spend some more time looking at the
DesignTimeServicesBuilder you will find this bit of code:
This means that the startup assembly just needs to include the
DesignTimeServicesReferenceAttribute assembly attribute pointing to the
IDesignTimeServices implementation. That's so much better. Here's an example of how the attribute should be used:
[assembly: DesignTimeServicesReference("EFCore.AuditExtensions.Common.EfCore.DesignTimeServices, EFCore.AuditExtensions.Common")]
Note: If your startup project is separated from the project containing your DbContext and you use the
-p|--project flags when using the dotnet-ef tool, the
DesignTimeServicesReference attribute can be located in the project specified with the
-p|--project flag (because of line #4 in the above snippet).
If you want to read the background behind the attribute and another example, visit the links below:
Cover photo by Daniel McCullough on Unsplash