Entity Framework – Generic repository Pattern – Part 1

The generic repository pattern has been a matter of discussion on the forums and SO. Developers are not convinced that it solves a problem, yet everyday SO has more questions about the pattern. Clearly, something is not right. I tried to implement the pattern in a way I thought fit. I changed my mind a million times during the process, that tells you that the process was not smooth. You can find several implementations of the pattern scattered all over the internet. I will not pass a opinion on the pattern. I would rather tell you what issues I faced and I how solved (or not) them.

First I created an IRepository and IUnitOfwork

   public interface IRepository
    {
        T Add(T entity);

        T Remove(T entity);

        T Update(T entity);

        IQueryable Query();        
    }

    public interface IUnitOfWork : IDisposable
    {
        void Commit();
    }

Next, let’s get the EF specific implementation up and running.


/// <summary>
    /// A EFRepository represents the repository for performing operations on the
    /// Entity using the EntityFramework.
    /// </summary>
    /// <typeparam name="T">T is the Entity</typeparam>
    public class EFRepository<T> : IRepository<T> where T : class
{
        /// <summary>
        /// This is set in the constructor and provides access to the underlying EntityFramework methods
        /// </summary>
        private DbSet<T> _dbSet;

        /// <summary>
        /// The context for working with the EntityFramework. This is set in the constructor.
        /// </summary>
        private DbContext _dataContext;

        /// <summary>
        /// Initialises a new instance of Repository for <see cref="T"/>
        /// </summary>
        /// <param name="unitOfWork">IUnitOfWork</param>
        /// <param name="dataContext">DbContext</param>
        /// <exception cref="ArgumentNullException">Throws ArgumentNullException if any of the arguments is null</exception>
        public EFRepository(IUnitOfWork unitOfWork, DbContext dataContext)
        {
            if (unitOfWork == null)
            {
                throw new ArgumentNullException("unitOfWork", "unitOfWork cannot be null");
            }

            if (dataContext == null)
            {
                throw new ArgumentNullException("dataContext", "dataContext cannot be null");
            }

            var EfUnitOfWork = unitOfWork as EFUnitOfWork;            
            _dataContext = dataContext;
            _dbSet = _dataContext.Set<T>();
        }

        /// <summary>
        /// Adds the specified Entity to the DbSet of the context.
        /// The Entity is inserted only when UnitOfWork is commited.
        /// </summary>
        /// <param name="item">The Entity to be added</param>
        /// <returns>The added Entity</returns>
        public T Add(T item)
        {
            return _dbSet.Add(item);
        }

        /// <summary>
        /// Removes the specified Entity from the DbSet of the context.
        /// The Entity is removed only when UnitOfWork is commited.
        /// </summary>
        /// <param name="item">The Entity to be removed</param>
        /// <returns>The Entity removed from the underlying DbSet</returns>
        public T Remove(T item)
        {
            return _dbSet.Remove(item);
        }

        /// <summary>
        /// Removes the specified Entity from the DbSet of the context.
        /// The Entity is removed only when UnitOfWork is commited.
        /// </summary>
        /// <param name="item">The Entity to be updated</param>
        /// <returns>the Entity removed from the underlying DbSet</returns>
        public T Update(T item)
        {
            var updated = _dbSet.Attach(item);
            _dataContext.Entry(item).State = EntityState.Modified;
            return updated;
        }

        /// <summary>
        /// Provides the caller with the underlying DbSet.
        /// </summary>
        /// <returns>An IQueryable to run queries against the underlying DbSet</returns>
        public IQueryable<T> Query()
        {
            return _dbSet;
        }

Follow this up with an implementation of EFUnitOfWork


/// <summary>
    /// Represents an IUnitOfWork for Entity Framework
    /// </summary>
    public class EFUnitOfWork : IUnitOfWork
    {
        /// <summary>
        /// The DbContext for the UnitOfWork
        /// </summary>
        private DbContext _context;

        /// <summary>
        /// Private field to check if the context has been disposed
        /// </summary>
        private bool _disposed;

        /// <summary>
        /// Initialises a new instance of EfUnitOfWork <see cref="EFUnitOfWork"/>
        /// </summary>
        /// <param name="context">DbContex for the UnitOfWork</param>
        public EFUnitOfWork(DbContext context)
        {
            if (context == null)
            {
                throw new UnitOfWorkException();
            }

            _context = context;
        }

        /// <summary>
        /// Method to e called when a UnitOfWork is to be committed.
        /// </summary>
        public void Commit()
        {
            _context.SaveChanges();
        }

        // Implement IDisposable.       
        public void Dispose()
        {
            Dispose(true);

            // Take yourself off the Finalization queue to prevent finalization code for object from executing a second time.
            GC.SuppressFinalize(this);
        }
       
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if (!_disposed)
            {
                // If disposing equals true, dispose all managed and unmanaged resources.
                if (disposing)
                {
                    // Dispose managed resources.
                    if (_context != null)
                    {
                        _context.Dispose();
                    }
                }             
            }

            _disposed = true;
        }
    }

    [Serializable]
    public class UnitOfWorkException : Exception
    {
        public override string Message
        {
            get
            {
                return "The parameter must be EFUnitOfWork";
            }
        }
    }

The above code is at Github
Are there alternatives ?
Oh yes plenty. Some just differ in implementation details , but others differ in philosophy altogether.
Next time I will blog about a different one that I thought of initially. Then later I will write about the problems we face.
Pick and choose what fits.

Advertisements

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