Limiting Your Entity Framework Models
If you're not reading Julie Lerman's Data Points column over at MSDN Magazine, you're missing out (in fact, I just realized that my recent column and her column are almost the same, except that hers covers more stuff). I especially appreciated her columns on Domain-Driven Design. And those columns got me thinking about where I should put my Entity Framework (EF) code.
The problem with code-first EF is writing out all the properties in all the entity classes and then applying the customizations those classes need. It's a lot of work: you don't want to do that more than once for any entity. And once you've got the entity built, its code may well be useful in other applications: you want to re-use. It's tempting strategy to package up all of your entity code and your DbContext class in a class library that you can copy from project to project.
The problem with that strategy is that, over time, that class library is going to contain references to every table and relationship in your organization's database. Because of that, your program is going to stop dead the first time you issue a query or call SaveChanges, as EF gathers information about all those tables and relationships (I have a partial solution to that problem coming up in another tip).
But, as Julie suggests in her Domain-Driven Design columns, your applications should use bounded domains: your application should just be using the entities that your application needs. And that led me to think about how to share my EF code while avoiding the performance hit. I realized, for example, that the performance hit isn't related to how many entities I've defined -- it's related to how many entities I've referenced in my DbContext object.
It seems to me that the class library I'm copying from one project to another should contain just the code that defines my entities (i.e., I should think of it as a strategic resource). My DbContext object, on the other hand, should be defined in my application and just reference the entities my application needs (it should be a tactical resource).
There are obviously some wrinkles here. Navigation properties that reference other entities are one example: If you include one entity in your DbContext object, you'll need to include all of the entities those navigation properties reference… and pretty soon all your entities are back in your DbContext object. Another example: EF 6's custom configurations (see my column on using them to make Complex Types useful). Like your entities, those customizations are both a lot of work, and because they're part of an entity's definition, something that should be treated as a strategic resource.
For navigation properties, partial classes may be the solution. First, define the DbContext object in the application, referencing just the entities you need. Second, define the entities in partial classes in a class library that's shared among applications; where necessary, this class library will also hold methods to configure these entities (these methods will accept a ModelBuilder object). Third, in your application, add partial classes for the entities you're using, but use these classes to define the navigation properties your application needs (and only those properties). Finally: also in your application, in your DbContext's OnModelCreating method, call out to those methods that configure the entities you need. You'll be able to reuse your entities with their configurations and still have a bounded domain that will load as fast as it can.
This sounds promising. I'll try it out in my next project (provided that I can get my client on board, of course. Or maybe not: what they don't know won't hurt me).
Posted by Peter Vogel on 04/21/2014 at 9:10 AM