More about how to fit the ObjectContext into apps
In my ongoing series of trying to repurpose / further broadcast important topics that come up in the forum, I thought folks might be interested in the discussion going on in this thread. A key part of this discussion is coming back to this question of ObjectContext lifetime that I discussed in this previous post.
Of course there's more than one way to do things, and Rick Strahl made a comment to that post pushing back on the idea of keeping a context around for an extended period of time because of concerns over things like building up an overall set of changes and then deciding that you want to "undo" part of those changes but not all of them before saving, etc. One approach he suggests is using a separate context per business object. The problems here, though, are around things like relationships which need to be tracked and modified somewhere. Yes, you can do this, and in some situations it may be better, but it certainly brings along its own complexity when it comes to managing all these contexts and context lifetimes.
For many scenarios I recommend using a single context (or one per thread if your app is multi-threaded). When it comes to these partial undo kinds of scenarios, I admit that there is some extra complexity--in fact there was some discussion on the team just in the last couple of days about looking into a number of related scenarios as we do planning for v2 which may lead to some additional features which will help here (how about a "RejectChanges" method which could be used to undo changes to an entity and its relationships without throwing out the whole context, for instance). Often times, though, those kinds of concerns can also be addressed by reducing the granularity of your units of work to the point where you can either commit an entire set of changes in the context or throw it out.
Taking this kind of approach allows you to sort of "go with the flow of the EF" which brings me back to the forum thread that started this post. In that thread, there's discussion about what belongs in what layer of the app--should you explicitly write a layer that hides all data access like we used to do? For most cases I would suggest "no". Part of the idea of the Entity Framework is that *it* provides the abstraction which hides the database. I think about it like this:
UI Layer / Top-level Application coordination
This is code which may reference lower layers but doesn't contain any EF framework code at all.
-----------------
Business Objects layer
These are your entities -- some of this code may be generated by the EF tools, but it is augmented with your own code supplied in partial classes, partial methods, event handlers, etc.
------------------
Data Layer
This is largely code which the EF supplies. It abstracts your business objects away from the details of the database. In past you would have written this pretty much all by hand, and this would be the only code that really interacts directly with ado.net. In the EF paradigm, you might often allow code to interact with EF framework code which takes the place of some of what you would have written by hand in this layer. The ObjectContext largely represents this layer, and you can extend it with its partial class as well as various event handlers and such so that you can customize the experience here, but you just don't have to write as much yourself.
Of course there's nothing that says you can't write your own data layer which encapsulates the EF code that I described as the data layer, but for many applications I tend to think that will make your life harder for relatively little benefit. One of the main reasons we would write a completely separate data layer in the past is that we wanted to isolate the business logic from changes in database schema and the like. The EF now does that for you with its mapping layer.
- Danny
Comments
Anonymous
March 02, 2008
PingBack from http://msdnrss.thecoderblogs.com/2008/03/02/more-about-how-to-fit-the-objectcontext-into-apps-2/Anonymous
March 02, 2008
Did you see this post at blogs.msdn.comAnonymous
March 03, 2008
Danny and I appear to be giving inconsistent advice on this regard in our recent weekend posts: Danny:Anonymous
March 03, 2008
Danny and I appear to be giving inconsistent advice on this regard in our recent weekend posts: DannyAnonymous
March 04, 2008
On change tracking and "RejectChanges"/Undos. It would be great to get this design right. In pre-history, we had a simplistic record-level Edit/Post definition of a 'unit of edit work' (ignoring the overall persistence greater unit of work), you couldn't even move to another record without 'Posting' or 'Cancelling'. Of course this was a pretty useless model in real life because a 'unit of edit work' may span multiple entities. RejectChanges is not an entity operation. However there is such a thing as a 'unit of edit work' and that such units may be driven by both GUI controls/actions and/or business rule effects. It is only at the boundaries of these units of edit work that 'edit savepoints' (undo-to points) make sense. (Multiple threads need to synchronize their units of edit work if undo is desired.) My fear is that a simplistic model of unit-of-edit-work is something useful for demo apps but once you hit that brick wall in real life, you end up working around it instead of using it. Similarly having an all-or-nothing accept/reject on the context is only useful for some scenarios and is not a generally useful feature.