Saturday, October 10, 2015

An Implementation of Unity of Work and Repository Pattern

 

Objective:

1. Keep a clean separation of concerns.

2. Implement business logic from acceptance test/ use case ( ATDD/ BDD )

3. A complete implantation on Repository and Unit of Work with IoC and Unit Testing (BDD).

.

Unity of Work Pattern:

One of the most common design patterns in enterprise software development is the Unity of Work. According to Martin Fowler, the Unity of Work pattern “Maintains  a list of objects affected by a business transaction and coordinates the writing out of changes and resolution of concurrency problems".

In a way, you can think of the Unit of Work as a place to dump all transaction-handling code. The responsibilities of the Unit of Work are to:

  • Manage transactions.
  • Order the database inserts, deletes, and updates.
  • Prevent duplicate updates. Inside a single usage of a Unit of Work object, different parts of the code may mark the same Invoice object as changed, but the Unit of Work class will only issue a single UPDATE command to the database.

The unity of work pattern isn't necessarily something that you will explicitly build yourself, almost every persistence tool already aware of it. The Entity Framework also have implementation of Unity of Work. SaveChanges() give us feature of unity work. Which allow us to save changes of list of objects together into database. But As I want decouple my business logic from database so the implementation of Unity of Work is

 

1 public interface IUnityofWork : IDisposable
2
3 {
4
5 void Commit();
6
7 }
8
9

The Commit() function work same as SaveChanges() in EntityFramework. If we use update records through context directly then we do not need really to maintain transaction but as we also have some existing stored procedure need to call and also for  bulk copy operation, we also need to maintain transaction explicitly. 

The implementation of Unity Of Work for Entity Framework as

 


1 1 public class UnityOfWorkBase
2 2 {
3 3 private bool _disposed = false;
4 4 protected DbContext Context;
5 5 public void Commit()
6 6 {
7 7 Context.SaveChanges();
8 8 }
9 9 public void Dispose()
10 10 {
11 11 Dispose(true);
12 12 GC.SuppressFinalize(this);
13 13 }
14 14 protected virtual void Dispose(bool disposing)
15 15 {
16 16 if (_disposed)
17 17 return;
18 18 if (disposing)
19 19 {
20 20 if (Context != null)
21 21 {
22 22 Context.Dispose();
23 23 Context = null;
24 24 }
25 25 }
26 26 _disposed = true;
27 27 }
28 28
29 46 }

 


Repository Pattern


Unity of Work provided me decoupling from database operation which we do not need to implement for Unit Testing scenario.

Next for decoupling database entity I have created repository for each entity which provide common functions as in memory object like List.

According to Martin Fowler, “Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects”.

Repository act-like in memory collection like List for .NET which provide common function like Add(), Remove(),  and enumeration functionality.  LINQ also provide extensive functionality on List and also Entity framework. 

The generic implementation of Repository pattern as follows:

 


1 1 public interface IRepository<T> where T : class
2 2 {
3 3 IQueryable<T> Query();
4 4
5 5 IEnumerable<T> FindAll();
6 6
7 7 IQueryable<T> Find(Expression<Func<T, bool>> predicate);
8 8
11 11 T First(Expression<Func<T, bool>> predicate);
12 12
13 13 void Add(T entity);
14 14 void Add(List<T> entity);
15 15
16 16 void Delete(T entity);
17 17
18 18 void Attach(T entity);
19 19
20 20 bool BatchInsert(IList<T> entity, string tableName);
21 21
22 22 }

BulkCopy is faster than normal insertion of multiple records as a batch. So in the repository I also have provided implementation. This implementation is suitable for both List and also DbSet.

The implementation of Repository for unit testing as follows:

 


1 1 public class TestRepository<T>:IRepository<T> where T:class
2 2 {
3 3 private IList<T> _repostiory = new List<T> ();
4 4 public IQueryable<T> Query()
5 5 {
6 6 return _repostiory.AsQueryable();
7 7 }
8 8
9 9 public IEnumerable<T> FindAll()
10 10 {
11 11 return _repostiory;
12 12 }
13 13
14 14 public IQueryable<T> Find(Expression<Func<T, bool>> predicate)
15 15 {
16 16 return _repostiory.AsQueryable().Where(predicate);
17 17 }
18 18
19 19
24 24 public T First(Expression<Func<T, bool>> predicate)
25 25 {
26 26 return _repostiory.AsQueryable().FirstOrDefault(predicate);
27 27 }
28 28
29 29 public void Add(T entity)
30 30 {
31 31 _repostiory.Add(entity);
32 32 }
33 33
34 34 public void Add(List<T> entities)
35 35 {
36 36 foreach (var entity in entities)
37 37 {
38 38 _repostiory.Add(entity);
39 39 }
40 40 }
41 41
42 42 public void Delete(T entity)
43 43 {
44 44 _repostiory.Remove(entity);
45 45 }
46 46
47 47 public void Attach(T entity)
48 48 {
49 49 throw new NotImplementedException();
50 50 }
51 51
52 52 public bool BatchInsert(IList<T> entities, string tableName)
53 53 {
54 54 Add(entities.ToList());
55 55 return true;
56 56 }
57 57 }

In the TestRepository example the repository is a in memory List object.

This repository is suitable for tables and views. But As we already have existing implication and some logics are in database. So I need to provide an interface to call stored procedure as well.

Repository for stored procedure will provide common function to execute stored procedure and retrieve value.

The interface of repository for stored procedure as

 


1 1 public interface IRepository_SP<T>
2 2 {
3 3 IEnumerable<T> ExecSqlQuery( params object[] parameters);
4 4 Int32 ExecSqlCommand(params object[] parameters);
5 5 }

The implementation of IRepostory_SP for unit testing is also simple as for query records it should return List and for executing command it return 0.

 


1 1 public class TestRepositorySp<T> : IRepository_SP<T> where T:class
2 2 {
3 3 public List<T> Items { get; set; }
4 4
5 5 public TestRepositorySp(List<T> items)
6 6 {
7 7 Items = items;
8 8 }
9 9
10 10 public IEnumerable<T> ExecSqlQuery(params object[] parameters)
11 11 {
12 12 return Items;
13 13 }
14 14
15 15
16 16 public int ExecSqlCommand(params object[] parameters)
17 17 {
18 18 return 0;
19 19 }
20 20 }

 


The example for mocking the stored procedure


1 var mocksecuritySp = new Mock<IRepository_SP<int>>();
2 mocksecuritySp.Setup(e => e.ExecSqlCommand(It.IsAny<ObjectParameter>()))
3 .Returns(0);
4 _testUnityOfWork.DeleteCommandRepositorySp = mocksecuritySp.Object;

This article is based on article https://msdn.microsoft.com/en-us/library/ff714955.aspx.

I wrote article on Specflow and FluentAssertion long time ago. Here is the link

http://ciintelligence.blogspot.ca/2014/05/atdd-acceptance-test-driven-development.html

3 comments:

  1. Hmm, it seems like your site ate my first comment (it was extremely long) so I guess I’ll just sum it up what I had written and say, I’m thoroughly enjoying your blog. I as well as an aspiring blog writer, but I’m still new to the whole thing. Do you have any recommendations for newbie blog writers? I’d appreciate it.
    AWS Training in Bangalore with Placements | AWS Training in Bangalore Cost
    AWS Training in Pune With Placement | AWS Devops Training in Pune
    AWS Online Training | AWS Online Training Cost
    AWS Training in Bangalore cost| Aws training in Bangalore Besant Technologies

    ReplyDelete

  2. Thank you for taking the time to discuss this informative content with us. I feel happy about the topic that you have shared with us. keep sharing your information regularly for my future reference. This content creates a new hope and inspiration with me. aws training in chennai | aws training in annanagar | aws training in omr | aws training in porur | aws training in tambaram | aws training in velachery

    ReplyDelete
  3. Really nice and very much implemented and useful too. it is really awesome and very much exclusive too. Thanks for sharing those valuable information. This is one of the best resources I have found in quite some time. Nicely written and great info.

    Aws Training in Chennai

    Aws Training in Velachery

    Aws Training in Tambaram

    Aws Training in Porur

    Aws Training in Omr

    Aws Training in Annanagar

    ReplyDelete