Implementation of Repository and Unit of Work Patterns using EF

The repository pattern is closely related to data access and allows us to have an abstraction of the implementation of data access in our applications, so that our business logic does not know or is uncoupled to the data source. In a nutshell this means that the repository acts as an intermediary between our business logic and our data access logic to be centralized in a single point, and thus be able to avoid redundancy code. This abstraction of the data access allows us to decouple and test a simpler way our code, since being uncoupled we can generate unit tests more easily.

One of the scenarios where we are most often use the repository pattern, is when we have multiple sources of data. For example we obtain much of the information in a relational database SQL Server, obtain other data from a web service and obtain other from a not SQL database for example. In this context the repository pattern will help us centralize access to each of these data sources for our client applications do not have to deal with this cumbersome work.

On the other side, Unit of Work aims to treat as a unit all those new objects, modified or deleted with respect to a data source. It is used to work with a set of persistent objects to be treated as a “unit” of work, stored in a database atomically.

In this case, when we use Unit Of work pattern with repositories, a work unit its main function is to gather all the repositories that make up our data layer and arrange them so that allow work in the same context of Entity Framework and to make transactions between repositories and all in the same transactions. The work unit is used by the business layer, which usually there rules that our application will be included.

ruof_1

Let’s start with the implementation of these two patterns.

FIRST WE DECLARE THE DOMAIN CLASSES

public class Customer
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string LastName { get; set; }
        public string Address { get; set; }

        public virtual ICollection<Order> Orders { get; set; }
    }

public class Order
    {
        public int Id { get; set; }
        public DateTime Date { get; set; }
        public bool  IsPrepaid  { get; set; }
        public virtual Customer Customer { get; set; }
        public int CustomerId { get; set; }

        public virtual ICollection<OrderLine> OrderLines { get; set; }
    }

public class OrderLine
    {
        public int Id { get; set; }
        public int Quantity { get; set; }
        public int OrderId { get; set; }
        public Product Product { get; set; }
        public int ProductId { get; set; }

    }

public class Product
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public decimal Price { get; set; }
    }

NOW WE CONFIGURE ENTITY FRAMEWORK (CODE FIRST)

we need to create the DBContext of the application, configure the differents types of our domain and the run the the following commands in the Package Manage Console:

  • add-migration initialMigration
  • update-database

public class AppContext : DbContext
    {
        public AppContext(): base("appConnectionString")
        {
            this.Configuration.LazyLoadingEnabled = false;
        }

        public virtual DbSet<Customer> Customers  { get; set; }
        public virtual DbSet<Order> Orders { get; set; }
        public virtual DbSet<OrderLine> OrderLines { get; set; }
        public virtual DbSet<Product> Products { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new CustomerConfiguration());
            modelBuilder.Configurations.Add(new OrderConfiguration());
        }
    }

IMPLEMENTATION OF THE GENERIC AND SPECIFIC REPOSITORIES

We will create a generic Repository class that implements all the common functionalities, the specific repositories will inheritance from this class.

Generic Repository:

public interface IRepository<T> where T : class
    {
        T Get(int id);
        IEnumerable<T> GetAll();
        T SingleOrDefault(Expression<Func<T, bool>> predicate);
        IEnumerable<T> Find(Expression<Func<T, bool>> predicate);
        void Add(T entity);
        void AddRange(IEnumerable<T> entities);
        void Remove(T entity);
        void RemoveRange(IEnumerable<T> entities);
    }

public class Repository<T> : IRepository<T> where T: class
    {
        protected readonly DbContext Context;

        public Repository(DbContext context)
        {
            Context = context;
        }

        public T Get(int id)
        {
            return Context.Set<T>().Find(id);
        }

        public IEnumerable<T> GetAll()
        {
            return Context.Set<T>().ToList();
        }

        public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
        {
            return Context.Set<T>().Where(predicate).ToList();
        }

        public T SingleOrDefault(Expression<Func<T, bool>> predicate)
        {
            return Context.Set<T>().SingleOrDefault(predicate);
        }

        public void Add(T entity)
        {
            Context.Set<T>().Add(entity);
        }

        public void AddRange(IEnumerable<T> entities)
        {
            Context.Set<T>().AddRange(entities);
        }

        public void Remove(T entity)
        {
            Context.Set<T>().Remove(entity);
        }

        public void RemoveRange(IEnumerable<T> entities)
        {
            Context.Set<T>().RemoveRange(entities);
        }
    }

Customer Repository:

public interface ICustomerRepository : IRepository<Customer>
    {
        Customer GetCustomerWithOrders(int idCustomer);
    }

public class CustomerRepository : Repository<Customer>, ICustomerRepository
    {
        public AppContext AppContext
        {
            get { return Context as AppContext; }
        }
        public CustomerRepository(AppContext context) : base(context)
        {

        }

        public Customer GetCustomerWithOrders(int idCustomer)
        {
            return AppContext.Customers.Include(x => x.Orders).SingleOrDefault(x =>           x.Id == idCustomer);
        }
    }

IMPLEMENTATION OF UNIT OF WORK

public interface IUnitOfWork : IDisposable
    {
        ICustomerRepository Customers { get;}
        IOrderRepository Orders { get;}
        int Complete();
    }

public class UnitOfWork : IUnitOfWork
    {
        public ICustomerRepository Customers { get; private set;}
        public IOrderRepository Orders { get; private set; }

        private readonly AppContext _context;

        public UnitOfWork(AppContext context)
        {
            _context = context;
            Customers = new CustomerRepository(_context);
            Orders = new OrderRepository(_context);
        }

        public int Complete()
        {
            return _context.SaveChanges();
        }

        public void Dispose()
        {
            _context.Dispose();
        }
    }

EXAMPLE OF USE

In order to show how we can use these patterns I have created a console application.

class Program
    {
        static void Main(string[] args)
        {
            using (var unitOfWork = new UnitOfWork(new AppContext()))
            {
                // ExampleA
                var customer1 = unitOfWork.Customers.Get(1);

                // ExampleB
                var orders = unitOfWork.Orders.GetOrdersWithLines(1);

                // ExampleC
                var customer = unitOfWork.Customers.GetCustomerWithOrders(1);
                if (customer != null)
                {
                    unitOfWork.Orders.RemoveRange(customer.Orders);
                    unitOfWork.Customers.Remove(customer);
                    unitOfWork.Complete();
                }

            }
        }
    }

This is just an example in how these patterns can be implemented. Hope this post can be useful for you guys.  You can find the code of this article HERE

Happy Coding!

References:
Asp.NET – Repository Pattern and Unit of Work
Repository Pattern – Martin Fowler

Advertisements
This entry was posted in Architecture and tagged , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s