Many .NET developers enjoy change tracking either since the days with the Data Sets or later with the Entity Framework. This document describes - in four posts - how to easily implement self-tracking entities that fit well into an MVVM application for WPF. As the solution relies on proven concepts, the basic ideas may also be applied to other technologies as well.
We focus especially at client-side development as this technology fits best there. The document describes the difference between change tracking and self-tracking entities by also providing implementations for both.
The entire article is split into five parts. The first post talks about the patterns behind and describes the change tracking implementation. The second post is dedicated to self-tracking entities. The third post depicts how to extend the self-tracking entities by validation concerns. The forth posts shows how to implement a composite entity and how to enhance validation by using the fluent validation API. And the fifth post demonstrates how to adapt self-tracking entities to an MVVM application:
Each post starts by describing the principals behind the respective solution. Then the solution’s expected behavior is documented with unit tests. The posts are then completed by presenting a fully functional implementation.
This post talks about the patterns behind self-tracking entities and describes a change tracking implementation.
Introduction
In the following paragraphs we clarify the terminology, especially the terms change tracking and self-tracking entities.
We talk about change tracking when are able to retrieve information about an object’s modifications, either directly on the affected object or through an other component. This applies to single objects as well to collections of objects. The later track the changes by keeping a list of operations that afterwards are executed - in a single transaction - on a data source.
Without self-tracking entities the entities are Plain Old C# Objects (POCOs) and do not track the changes internally. The developer has to store the modifications in an own component. This component usually consists of four sets, one for the newly added (inserted), one for the changed (updated), one for the removed (deleted), and one for the unchanged entities. The developer has to keep those sets in sync, and e.g. would call Update(author) for updating an existing author.
Collections allowing to execute a set of operations in a single transaction are known as Unit-of-Work. We will introduce the pattern in more detail later.
Self-tracking entities are an extension to this definition where both the Unit of Work and the entities are enhanced to handle certain changes without requiring an interaction from the developer. The entities manage their status autonomous and they are observable. In case of a change they notify their observers. The observers - e.g. the Unit of Work - then have the possibility to trigger further actions, i.e. to update their entity sets accordingly. But self-tracking entities do not come without any cost as this logic brings additional complexity.
The following two unit tests depict the difference between change tracking and self-tracking entities (in this order).
Before modelling our component, we start consulting the most widely used patterns to see if we can borrow some proven concepts.
Repository Pattern
We need a component that provides data access in a uniform way, independent from the data source. Such a component is described by the Repository Pattern.
As per Martin Fowler’s definition of the Repository Pattern, [The repository] mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.. In other words, the repository provides means for accessing, updating, adding, and deleting entities through the same object.
The pattern does not provide an exact interface definition. But the following one should fit our needs.
Unit of Work Pattern
Next we define a component that handles change tracking. The Unit-of-Work Pattern describes exactly such a component, including its interface.
The Unit-of-Work maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.. One solution for implementing this definition is to keep an entity set for each kind of operation.
For our needs we slightly enhance the above interface with the following methods, properties, and events, to make it resemble the change tracking API provided by the good old Data Sets.
The Unit of Work Repository
As we are not going use a Repository without the functionality of a Unit of Work, we create a new interface IUnitOfWorkRepository that implements both the IUnitOfWork and IRepository interfaces. From now on both terms will refer to this component.
Have you noticed that with AddItem (part of IRepository) and Insert (part of IUnitOfWork) we have two methods that on the first sight provide a similar functionality? As AddItem is not part of the IUnitOfWork interface it will not affect any information related to change tracking, whereas Insert would change the HasChanges flag of the repository to TRUE. As you can see from the interface definition it will even raise a HasChangesChanged event, in case the repository was not yet dirty (the event will only be raised once).
In summary the AddItem method is used to fill the repository with entities from a data source. When you have to insert, update, or delete items afterwards then you will use the corresponding methods from the IUnitOfWork interface.
Unit Tests
In the spirit of Test Driven Development (TDD) we describe the unit tests before starting the implementation. The unit tests reflect the expected behavior in detail and assert a high level of quality, especially if combined with Continous Integration (CI).
Implementation
Now we are going to implement the abstract base repository class RepositoryBase. It actually only keeps a collection of the available items and delegates the work related to change tracking - according to the Single Responsibility Principle - to a component called IChangeTracker<TEntity>, which is described later.
Please note the virtual methods OnItemAdded and OnItemRemoved. Those methods allow child classes to hook into the workflow. Generally this is a nice approach to design base classes but we will also need those two methods later for our implementation of self-tracking entities.
The methods defined in IUnitOfWork are implemented as described in the following code listing. Whenever one of those methods is called, we check for any occurrence in any other entity set and perform some cleanup. E.g. if we try to call update on an previously deleted entity, we are allowed to remove that entity from the deleted set as well. We also have to make sure that calling update will not add the entity to the updated set in case an item has been inserted, as we first have to insert it anyhow. And so on, I think all of the possible cases are self-explanatory and documented in the below code listing.
The missing methods are implemented as follows:
Change Tracker
The IChangeTracker actually stores the entity status information. It is important to keep the data immutable so that nobody else can manipulate the data without using the designated methods.
As mentioned above the class has to be immutable and so we have to make sure instead of returning references to our collections we return copies of them. We also use Hash Sets as entity collections for performane reasons as we expect to perform many read operations with the corresponding Contains methods.
Immutable Collections
We have mentioned earlier that the collections returned by a IChangeTracker<TEntity> or a IRepository<TEntity> implementation should be immutable to prevent unwanted manipulations by clients. As a caller may get access to the source collection by casting the returned IEnumerable it is not enough to simply change the method signatures from a ICollection extension to IEnumerable.
The only solution appears to be to return a copy of the underlying collection. Of course this means a huge overhead as we have to iterate over all items each time a copy is created. Furthermore a new object is instantiated for each request which increases memory consumption and may cause pressure on the garbage collector.
Fortunately since December 2012 Microsoft delivers the Immutable Collections library as nuget package for the .NET framework 4.5 which guarantees that the collections may not be changed at all but can be efficiently mutated by allocating a new collection that shares much of the same memory with the original. As this approach seems to improve the overall performance we will rewrite the corresponding parts to use the new collections.
The method signatures should return IReadOnlyCollection instead of IEnumerable to make it transparent that we are going to return a non-writable collection.
As invoking Add or Remove will not affect the collection but rather return a new instance, the implementation changes as follows:
Review and Outlook
At this point we have a working implementation - also as download - of the Unit of Work pattern which requires to manually keep the entity sets in sync. Please run the unit tests again and make sure all tests succeed.
We now have assembled the fundament for implementing self-tracking entities. On one side it will reduce the developer’s work to interact with the entities, on the other side it adds further complexity we have to handle. But especially for developing client-side applications with the MVVM pattern in WPF you will love it. Therefore let’s dive into the next post, Part 2 - Entities!