Thursday, May 7, 2020

Using a unit of work for transactional operations

This article shows an example of how a unit of work can be used in an application with a very basic example. If you have chosen to work with the repository pattern and have concerns about transactional operation, this article might be for you.

Initial context


Say we have an e-Shop where clients can place orders. Our database contains tables for our customers, our suppliers and the orders. A first approach based on the repository pattern would look like the following.


The application controller directly accesses the repositories and updates all the tables sequentially when the client places the order. As each access to the database is isolated, it cannot do all the updates together. This structure works but is subject to inconsistencies. The controller needs to perform the updates in the right order and the desired relations are built one at a time. If the application crashes or if the transaction is somehow interrupted before completion, my database is partially updated and contains segments of information that might not be valid anymore.

Unit of work to the rescue


"A unit of work keeps track of everything you do during a business transaction that affect the database"


On this new diagram, the domain logic accesses the unit of work instead of the repositories. The unit of work encapsulates and exposes the repositories required for the order. With this representation, the purpose of the unit of work becomes clearer:

The client has only one method to make them persistent which is Complete()

The implementation of this method can actually bring the notion of transaction into the picture which is safer in terms of data consistency.

Theoretically, your application will need several unit of works to group all the data that changes together in one place. It does not mean that a repository can only be accessible from one unit of work. We can imagine here a second unit of work to manage the user accounts that would encapsulate CustomerSecuritySettingsRepository and CustomerRepository as well. Make sure you're dealing correctly with concurrent accesses in your repositories and you're good to go.

Here is how the unit of work reflects in most popular persistence tools:
* ITransaction in NHibernate
* DataContext in LINQ to SQL
* ObjectContext in EntityFramework

Wrapping-up


This article demonstrated a very easy setup of the "unit of work pattern" to efficiently and consistently do changes in your persistent storage. Martin Fowler depicts it very well here:
https://martinfowler.com/eaaCatalog/unitOfWork.html


 
biz.