ArticleDirectory
- Create an infrastructure
- Create model
- Establish repository to persist business entities
What is the unit of work mode?
The unit of work mode is used to maintain a list of business objects that have been modified (added, deleted, or updated) by business transactions. The unit of work mode coordinates the persistence of these changes and the concurrency of all tags. The benefit of using the unit of work mode in the data access layer is to ensure data integrity. If a problem occurs during the persistence of a series of business objects (they belong to the same thing), all modifications should be rolled back to ensure that the data is always in a valid state.
To demonstrate the unit of work mode, a simple banking domain is used to model the transfer between two accounts. The interaction between the service layer (accountservice) and the resource layer (accountrepository) that uses the unit of work mode (to ensure that the transfer is committed as an atomic thing) is provided.
Remember this image, because the followingCodeThe logic is implemented according to the definition of this figure.
Create an infrastructure
- Next, we will write the solution code. First, we will create all the supporting infrastructure code for the unit of work mode.
Public InterfaceIaggregateroot {}
The iaggregateroot interface actually belongsMark InterfaceThis interface acts as the class and MethodMetadataThe resource library we built only persistently implements the Business Objects of the iaggregateroot interface, so the implementation of unit of workUse the iaggregateroot interface to reference any business entity involved in an atomic transaction.
- Add another iunitofworkrepository interface, which is used for persistent operations:
Public InterfaceIunitofworkrepository {VoidPersistcreationof (iaggregateroot entity );VoidPersistupdateof (iaggregateroot entity );VoidPersistdeletionof (iaggregateroot entity );}
- Then, add the iunitofwork interface to the infrastructure project:
Public InterfaceIunitofwork {VoidRegisteramended (iaggregateroot entity, iunitofworkrepository unitofworkrepository );VoidRegisternew (iaggregateroot entity, iunitofworkrepository unitofworkrepository );VoidRegisterremoved (iaggregateroot entity, iunitofworkrepository unitofworkrepository );VoidCommit ();}
It is worth noting that the iunitofwork interface requires iunitofworkrepository when registering and modifying/adding/deleting. In this way, the unit of work can delegate the truly persistent work to appropriate implementations during submission.
- Finally, add unitofwork to the infrastructure project to implement iunitofwork:
Public Class Unitofwork: iunitofwork { Private Dictionary <iaggregateroot, iunitofworkrepository> Addedentities; Private Dictionary <iaggregateroot, iunitofworkrepository> Changedentities; Private Dictionary <iaggregateroot, iunitofworkrepository> Deletedentities; Public Unitofwork () {addedentities = New Dictionary <iaggregateroot, iunitofworkrepository> (); Changedentities = New Dictionary <iaggregateroot, iunitofworkrepository> (); Deletedentities = New Dictionary <iaggregateroot, iunitofworkrepository> ();} Public Void Registeramended (iaggregateroot entity, iunitofworkrepository unitofworkrepository ){ If (! Changedentities. containskey (entity) {changedentities. Add (entity, unitofworkrepository );}} Public Void Registernew (iaggregateroot entity, iunitofworkrepository unitofworkrepository ){ If (! Addedentities. containskey (entity) {addedentities. Add (entity, unitofworkrepository );};} Public Void Registerremoved (iaggregateroot entity, iunitofworkrepository unitofworkrepository ){ If (! Deletedentities. containskey (entity) {deletedentities. Add (entity, unitofworkrepository );}} Public Void Commit (){ Using (Transactionscope scope = New Transactionscope ()){ Foreach (Iaggregateroot entity In This . Addedentities. Keys ){ This . Addedentities [entity]. persistcreationof (entity );} Foreach (Iaggregateroot entity In This . Changedentities. Keys ){ This . Changedentities [entity]. persistupdateof (entity );} Foreach (Iaggregateroot entity In This . Deletedentities. Keys ){ This . Deletedentities [entity]. persistdeletionof (entity);} scope. Complete ();}}}
The unitofwork class uses three dictionary variables to track modifications to the generation of business entities. The first dictionary corresponds to the entity added to the data storage. The first dictionary traces the updated entity, and the third dictionary processes the object deletion, iunitofworkrepository that matches the object key in the dictionary will be saved and usedCommitMethodTo call the repository object. The object contains the code of the truly Persistent Object.. The commit method traverses each dictionary and calls the corresponding iunitofworkrepository method (passing object references ). The work in the commit method isTransactionscopeCode packaging. If an exception occurs when a task is executed in iunitofworkrepository, all work will be rolled back and data storage will remain in the original state.
Create model
- Add a new class account to the model to indicate a bank account. To facilitate demonstration, the following is a simple process:
Public class account: iaggregateroot {public decimal balance {Get; Set ;}}
- To make accout persistent, add the iaccountrepository interface:
Public InterfaceIaccountrepository {VoidSave (account Account );VoidAdd (account Account );VoidRemove (account Account );}
- Add the accountservice service class to coordinate the transfer between two accounts.
Public Class Accountservice { Private Iaccountrepository _ accountrepository; Private Iunitofwork _ unitofwork; /// <Summary> /// Accountservice uses its constructor to implement dependency Injection /// </Summary> /// <Param name = "accountrepository"> </param> /// <Param name = "unitofwork"> </param> Public Accountservice (iaccountrepository accountrepository, iunitofwork unitofwork) {_ accountrepository = Accountrepository; _ unitofwork = Unitofwork ;} /// <Summary> /// Transfers funds between two accounts /// </Summary> /// <Param name = "from"> </param> /// <Param name = "to"> </param> /// <Param name = "amount"> </param> Public Void Transfer (account From , Account, Decimal Amount ){ If ( From . Balance> = Amount ){ From . Balance-=Amount; To. Balance + = Amount; _ accountrepository. Save ( From ); _ Accountrepository. Save (to); _ unitofwork. Commit ();}}}
Next, it calls the account repository to save the two accounts. Finally, it calls the commit method of the unit of work instance to ensure that the transaction is completed as an atomic unit of work.So the next point is how repository interacts with the unit of work.
Establish repository to persist business entities
Public Class Accountrepository: iaccountrepository, iunitofworkrepository { Private Iunitofwork _ unitofwork; Public Accountrepository (iunitofwork unitofwork) {_ unitofwork = Unitofwork ;} Public Void Save (account Account) {_ unitofwork. registeramended (account, This );} Public Void Add (account Account) {_ unitofwork. registernew (account, This );} Public Void Remove (account Account) {_ unitofwork. registerremoved (account, This );} Public Void Persistupdateof (iaggregateroot entity ){ // Ado.net or EF, NH for persistence } Public Void Persistcreationof (iaggregateroot entity ){ // Ado.net or EF, NH for persistence } Public Void Persistdeletionof (iaggregateroot entity ){ // Ado.net or EF, NH for persistence }}
OK, so that the unit of work mode can be set up,AccountrepositoryImplementedIaccountrepositoryAndIunitofworkrepositoryInterface, iaccountrepository method implementation simply delegate workUnit of work(Pass in the object to be persisted and reference of repository), and finally, callUnit of workClassCommitIn fact, the unit of work references repository.IunitofworkrepositoryFor the persistence operation, you can use ado.net, EF, and NH.
Looking back, let's look at this picture. The unit of work is just like this: