In my last post I showed the transformation from the generic repository to the unit of work pattern only. I received an interesting question in the comment section.
Looks nice so far. But didn’t you mix up and simplify things a little bit too much here? For me the Repository is the separation of Domain Objects and Persistent Entities. It’s also a separation of the client from the used persistency technology (either NHibernate, EF, SharePoint, ADO.NET, WebService or whatever). As client side calling code, I really don’t care, where and how my data is stored.
Of course the interface of the repository should be expressive enough and not generic as this was mentioned many times by you and the different contributors.
But why do you mix together the Repository with the UnitOfWork and the transaction handling? Is it something NHibernate specific? Did I miss your point?
I want to clarify my point in this blog post.
I don’t think I mixed up a little too much. The implementation I show in the blog post is moving from the repository pattern to the unit of work pattern. The article shows that a repository is an unneccesary abstraction which can be removed. Let us look into the formal definition of repositories and unit of work:
“A REPOSITORY represents all objects of a certain type as a conceptual set (usually emulated). It acts like a collection, except with more elaborate querying capability. Objects of the appropriate type are added and removed, and the machinery behind the REPOSITORY inserts them or deletes them from the database. This definition gathers a cohesive set of responsibilities for providing access to the roots of AGGREGATES from early life cycle through the end.”
[…] “Although the REPOSITORY will insert into and delete from the database, it will ordinarily not commit anything. It is tempting to commit after saving, for example, but the client presumably has the context to correctly initiate and commit units of work. Transaction management will be simpler if the REPOSITORY keeps its hands off.”
– Domain Driven Design: Tackling complexity in the heart of the software –
and the unit of work
“When you’re pulling data in and out of a database, it’s important to keep track of what you’ve changed; otherwise, that data won’t be written back into the database. Similarly you have to insert new objects you create and remove any objects you delete.”
[…] “A Unit of Work keeps track of everything you do during a business transaction that can affect the database. When you’re done, it figures out everything that needs to be done to alter the database as a result of your work.”
– Patterns of Enterprise Application Architecture –
As we see the two definitions closely relate to each other. The repository does not only offer querying capabilities but also allows to add and remove entities. But Repositories itself should not commit operations on the database. That is the responsibility of the unit of work. But the unit of work itself has to keep track of changes (add, removes and updates). Even querying requires the usage of an explicit business transaction (aka unit of work scope), not having an explicit transaction can result in implicit (and autocommiting transactions, see (1)). Therefore for querying we should also wrap these in a unit of work scope. I always prefer being explicit about my unit of work boundaries.
So what I did in the end is: I moved the add, remove and update responsibility solely to the unit of work (as it has to keep track of changes anyway). When you do that all what is left on the repository is the querying capability. Querying also needs explicit unit of work boundaries (business scope) and this can also be moved to the unit of work. Hope that helps.
NHibernate: “When we don’t define our own transactions, it falls back into implicit transaction mode, where every statement to the database runs in its own transaction, resulting in a large performance cost (database time to build and tear down transactions), and reduced consistency.”
EF: “When performing a SaveChanges operation, the Entity Framework implicitly wraps all of the commands in a database transaction; however, you can take control of transactions as well.”