Unit of Work with Lazy loaded Repositories (EF Code First)

Share on Facebook

The Unit of Work pattern is particularly useful for managing data context disposal when using generic repositories. There are different approaches online for using the Unit of Work pattern with Asp.Net MVC Controllers. Some developers pass in a Unit of Work interface as well as a repository interface as parameters to the controller. Others prefer to manifest the data repositories (generic), as properties of the Unit of Work. In most cases where the latter is used, I find most people pre-define the repositories. ie, iUoW.productRepository or iUoW.customerRepository. So I set out to create a generic lazy loaded GetRepository<T> on the UoW interface, to load the Repository<T> data repositories on demand.

The interface is defined as follows:

 public interface IUoW
    {
        IRepository GetRepository() where TEntity : class, new();
        void Commit();
        void Dispose();
    }

And it is implemented like so:

using System;
using System.Collections.Generic;
using RollCall.Entities;

namespace RollCall.Pages.Model
{
    public class UoW : IDisposable, IUoW
    {
        private readonly RollCallContext _context = new RollCallContext();
        private static readonly IDictionary Repos = new Dictionary();

        public IRepository GetRepository() where TEntity : class, new()
        {
            if (Repos != null)
            {
                if (!Repos.ContainsKey(typeof(TEntity)))
                {
                    var repo = new Repository(_context);
                    Repos.Add(typeof(TEntity), repo);
                }
                return (Repository)Repos[typeof(TEntity)];
            }
            else return null;
        }

        public void Commit()
        {
            _context.SaveChanges();
        }

       #region idisposable
        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    _context.Dispose();
                }
            }
            this.disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion
       
    }
}

Where the generic repository is defined as:

public interface IRepository where TEntity : class,new()
    {
        IEnumerable Get(
            Expression> filter = null,
            Func, IOrderedQueryable> orderBy = null,
            string includeProperties = "");

        TEntity GetById(object id);
        void Insert(TEntity entity);
        void Delete(object id);
        void Delete(TEntity entityToDelete);
        void Update(TEntity entityToUpdate);
    }

And the generic repository is implemented like so:

public class Repository : IRepository where TEntity : class, new()
    {
        internal RollCallContext Context;
        internal DbSet DbSet;

        public Repository(RollCallContext context)
        {
            this.Context = context;
            this.DbSet = context.Set();
        }

        public virtual IEnumerable Get(
            Expression> filter = null,
            Func, IOrderedQueryable> orderBy = null,
            string includeProperties = "")
        {
            IQueryable query = DbSet;

            if (filter != null)
            {
                query = query.Where(filter);
            }

            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }

            if (orderBy != null)
            {
                return orderBy(query).ToList();
            }
            else
            {
                return query.ToList();
            }
        }

        public virtual TEntity GetById(object id)
        {
            return DbSet.Find(id);
        }

        public virtual void Insert(TEntity entity)
        {
            DbSet.Add(entity);
        }

        public virtual void Delete(object id)
        {
            TEntity entityToDelete = DbSet.Find(id);
            Delete(entityToDelete);
        }

        public virtual void Delete(TEntity entityToDelete)
        {
            if (Context.Entry(entityToDelete).State == EntityState.Detached)
            {
                DbSet.Attach(entityToDelete);
            }
            DbSet.Remove(entityToDelete);
        }

        public virtual void Update(TEntity entityToUpdate)
        {
            DbSet.Attach(entityToUpdate);
            Context.Entry(entityToUpdate).State = EntityState.Modified;
        }
    }

Where RollCallContext is a subclass of the Entity Framework Code First base class DbContext.

Please let me know if there are any pitfalls with the approach by leaving your comments.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListkick it on DotNetKicks.comTwitThis

Comments are closed

About Me

When not scratching my head for solutions to software challenges, I spend my time playing with my little boy - Michael Jnr.

Quotations

"A fanatic is one who can't change his mind and won't change the subject."
Sir Winston Churchill

Donate with PayPal - it

Calendar

<<  February 2012  >>
MoTuWeThFrSaSu
303112345
6789101112
13141516171819
20212223242526
2728291234
567891011

View posts in large calendar

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2005 - 2012

Search