The information in this post is out of date.
Visit msdn.com/data/ef for the latest information on current and past releases of EF.
Self-tracking entities have several utility methods to do things like AcceptChanges and StartTracking which work over a single entity. However, there are cases where it would be nice to be able to do similar operations but on a set of entities instead of just one. In this post, I’ll describe two options for performing operations on sets of entities, one that works with entities that are attached to an ObjectContext, and one more general graph iterator solution based on a T4 template. Both options can be applied to all kinds of entities including self-tracking entities, POCOs, and EntityObject entities, but the samples I show will target common utility methods that can be used with self-tracking entities such as AcceptAllChanges and StartTrackingAll.
The ObjectStateManager Option
Many operations on sets of entities can be accomplished just by using the Entity Framework’s ObjectStateManager. The ObjectContext class uses an ObjectStateManager to track changes to entities and to do identity resolution, and exposes the ObjectStateManager as a public property. You can get access to the entities in the ObjectStateManager via the GetObjectStateEntries method which returns an IEnumerable<ObjectStateEntry>. An easy way to get at all of the entities is to write extension methods that use LINQ to Objects to perform queries against the entries in the ObjectStateManager.
One example of when this is useful is to turn on change tracking for every self-tracking entity that is being tracked by an ObjectContext. To do this, we’ll query the ObjectStateManager and cast each entity to an IObjectWithChangeTracker and call StartTracking on it:
These extension methods that do LINQ to Objects queries over the ObjectStateManager can be quite powerful, but can often be difficult to write and as I mentioned, can only be used if everything is tracked by an ObjectContext. The next section describes an alternative approach using a code generated graph iterator that does not involve the ObjectContext or ObjectStateManager.
The Graph Iterator Option
While the ObjectStateManager option is useful when entities are attached to an ObjectContext, it is not useful when you want to perform an operation on the client where creating an ObjectContext is just extra overhead (or worse, not even available like in the case of Silverlight). What we’d really like is a lightweight class that knows about all entities in a graph of related entities. I have created such a class as part of a T4 template that you can download using the link at the bottom of this post, and describe how it works and why it’s a T4 template below. What you need to do to get started is to download the above template, add it to your C# Visual Studio project, and point it at your edmx model file. Then you’ll be able to write extension methods like AcceptAllChanges to call AcceptChanges on every entity, HasChanges to tell if there are any changes in any entity in the set, or StartTrackingAll to turn change tracking on for all entities. For example:
The following sections describe how the template works in detail.
The NorthwindEntityIterator Class
The basic iterator class has a few core components:
· A private list to store entities
· A mechanism to traverse different kinds of entities and add them to the list of entities
· Methods to construct an iterator and execute operations over the set of entities in the iterator list
First let’s look at the main iterator class, which I’ve called NorthwindEntitiesIterator because it will help iterate over entities from the Northwind model. There is a private field _items for the list, and the class exposes two views of this list as properties: one public property as a read-only view, and one protected property as a writable view (so the contents of list cannot be modified after the list is populated):
To populate the list of entities, the NorthwindEntitiesIterator uses a variation of the visitor design pattern that takes advantage of some new language features in .NET 4.0. Most visitor implementations require some change to the entity classes, but with the dynamic feature in .NET 4.0, this isn’t necessary. The key requirement for the visitor mechanism is to traverse the related entity graph and add each entity to the list, but to only add each entity once. It is fairly common for a graph or related entities to have cycles: a Customer has an Orders collection and each Order has a reference to a Customer, and we want to be able to stop traversing when we detect such a cycle.
The NorthwindEntitiesIterator’s visitor mechanism starts with a Visit method that takes an entity as a dynamic object. In C# in .NET 4.0, all object types can be cast to a dynamic so the method can accept any of the entity types in the model. The trick though is that once the entity is cast as a dynamic, it can be passed back to statically typed methods as long as such a method exists at runtime. To illustrate this, let’s look at the implementation of the Visit method:
The Visit method first checks to see if the entity has already been visited by looking in the WritableItems collection which is how it detects cycles and knows how to stop traversing the entity graph. If the entity has not yet been visited, the entity (which is a dynamic object in this method) is passed to the NorthwindEntitiesExtensions.Traverse method.The NorthwindEntitiesExtenions class is a static class with a bunch of static Traverse extension methods. The Traverse method is responsible for knowing how to get from an entity to its related entities, so there is a Traverse extension method for each entity type. This is where the power of T4 templates comes in because the Traverse methods can be generated by the template since the template knows all the entity types and their navigation properties. Here is an example of a Traverse method for the Territory entity in the Northwind model which has a reference to a Region entity and a collection of Employee entities:
All the Traverse method does is look at the navigation properties on the Territory and call the NorthwindEntitiesIterator.Visit method on them. Once the first Visit method call returns, all entities in the graph have been added to the _items collection and we can start executing operations on them.
The NorthwindEntitiesIterator has a few methods to make creating the iterator and executing operations over it easy. First, there is a factory method which creates an iterator and populates its list with entities:
There are also several Execute methods that take an iterator and an Action<T> and execute the action on all entities of the type T. For example:
Writing Self-Tracking Entity Utility Methods
Now that we have the NorthwindEntitiesIterator, we can write some utility methods for common self-tracking entities tasks. Sometimes it is useful to start and stop change tracking on all related entities. This is typical when the scenario calls for you to perform change tracking when serialization is not involved such as in a service or workflow method. These methods can be written with just a few lines of code using the NorthwindEntitiesIterator.Execute method: simply create an iterator instance for the entity graph and execute an action on all IObjectWithChangeTracker instances to StartTracking or StopTracking:
To use the StartTrackingAll method, you could then write something like this:
In client-server applications, a common usage pattern with self-tracking entities is to re-use entities on the client after a service call to Update a set of entities. To re-use an entity on the client after it has been updated, you need to call AcceptChanges on the entity. To re-use a graph of related entities, you need to call AcceptChanges on all the related entities and this is where the NorthwindEntitiesIterator can help to write an AcceptAllChanges extension method. The implementation is very similar to StartAllTracking:
One might use this method like this on the client to call an Update service method and then accept all the changes on that entity graph:
As a final example, one optimization to the client-server ClientUpdate example above is to only actually call the service’s Update method if the Customer c or any of its related entities have changes in them. To do this, we need a method that looks over every entity in the graph and checks whether there are any changes. The NorthwindEntitiesIterator can again help us implement this method:
First we create a NorthwindEntitiesIterator and then we can iterate over the contents and check whether any of the entities have a state other than Unchanged. This makes the optimization to our ClientUpdate method straightforward:
There are a lot of good reasons to perform operations on a set of related entities and so having a good graph iterator solution is very useful when implementing these methods. When you have things attached to an ObjectContext, it’s possible to use LINQ to Objects to query the ObjectStateManager.
A more general solution is to use the graph iterator template (see link below, you’ll need to rename it to “Iterator.tt”), which can be used anywhere the entities are used, even when there is no ObjectContext, but does require you to include the template in your project. In an upcoming blog post, I’ll outline some additional uses for the template based iterator that helps with re-using self-tracking entities on the client even when you need to deal with server generated values during update service calls.
If there are more self-tracking entities scenarios you’d like to hear about, just let me know.
Entity Framework Team