I completed converting my moderately complex sub-model (24 entities) from the database-first style to code-first style this week. The results are pretty encouraging.
I find your lack of faith disturbing
The use of foreign key associations, POCO’s and the Fluent API vastly simplified the resulting code. Not that I didn’t encounter my share of learning curve struggles. The fluent api syntax for declaring relationships is a bit clumsy, and the difference between declaring properties as virtual or not and its resulting impact on lazy load behavior confused me on at least one occasion. Notwithstanding those, the bulk of the effort was simply the brute typing involved in re-implementing all the class, repositories and relationships, as well as refactoring tests to use the new code. The EF 4.x POCO Entity Generator gave me a really good starting point, although it didn’t allow me to pick which tables, instead generating the whole database.
All too easy
What I found most compelling with POCOs, is that I no longer needed to jump through all the hoops to detach and re-attach object graphs. You may recall we used this approach, Reattaching Entity Graphs with the Entity Framework, to handle this problem in EF v1. Apparently, and it kind of makes sense with POCOs, that detaching and re-attaching is less of an issue. My code-first repositories are so much simpler that I’m suspicious that either I’ve missed something or my chosen sub-model wasn’t sufficiently complex enough to surface the still lurking issues of detaching objects. Then again, one thing I haven’t attempted yet is persisting a complex object graph as one unit, relationships and all.
Asteroids do not concern me
Once the object leaves the context its essentially detached. One odd side-effect of this and lazy loading is that accessing a lazy property (even to check if its null) outside of the context results in an exception. There doesn’t appear to be a good way to check if properties are loaded outside of the context. To handle this I disabled lazy loading, which might seem extreme, except that I was already being explicit using Include(), and having EF attempt to lazy load detached objects doesn’t serve much purpose.
Another oddity I haven’t quite grokked is that foreign key associations don’t appear to stay in sync with their ID properties even after a SaveChanges() (e.g. if I update the StateId on an Address, the Address.State association doesn’t seem have the correct State after the persistence). Its not a feature I’ve thus relied on so its not an issue in this case but something I’ll want to understand better if I go forward.
Impressive, most impressive
Overall, I’m very impressed with combination of code-first, POCO and the fluent api in EF 4.3. I don’t see any reason not to convert our existing EF code to this approach, other than the time, effort and risk. It may not be flawless, but it’s a considerable improvement over the contorted v1 style approach currently employed. There are two additional points of inspiration gleaned from this effort:
- The POCOs appear as if like they could just as easily work with NHibernate as with EF. They have no dependency on or direct relationship with EF (thanks the the fluent api) and all the properties are virtual.
- There is a striking similarity between the POCO objects and our Domain objects in many cases, In some cases, the POCO object is nearly identical to the Domain object that its hydrating. This suggests to me that we may be able to collapse the two layers.
Perhaps I can find new ways to motivate them
Next up I’m going to try to implement this same sub-model using the same POCO objects, but this time using Fluent NHibernate. NHibernate is more mature, supports more databases, and has Level 2 cache support baked in. All else being equal, NHibernate might be the better choice, so I want to see how equal all else is.
At some point I should probably explain what I’m trying to accomplish with all of this.