Building a Repository Pattern against an EF 5 EDMX Model - Part 1

Posted by Juan on Geeks with Blogs See other posts from Geeks with Blogs or by Juan
Published on Wed, 03 Oct 2012 10:13:31 GMT Indexed on 2012/10/03 21:38 UTC
Read the original article Hit count: 239

Filed under:

I am part of a year long plus project that is re-writing an existing application for a client.  We have decided to develop the project using Visual Studio 2012 and .NET 4.5.  The project will be using a number of technologies and patterns to include Entity Framework 5, WCF Services, and WPF for the client UI.

This is my attempt at documenting some of the successes and failures that I will be coming across in the development of the application.

In building the data access layer we have to access a database that has already been designed by a dedicated dba. The dba insists on using Stored Procedures which has made the use of EF a little more difficult.  He will not allow direct table access but we did manage to get him to allow us to use Views. 

Since EF 5 does not have good support to do Code First with Stored Procedures, my option was to create a model (EDMX) against the existing database views.   I then had to go select each entity and map the Insert/Update/Delete functions to their respective stored procedure.

The next step after I had completed mapping the stored procedures to the entities in the EDMX model was to figure out how to build a generic repository that would work well with Entity Framework 5. 

After reading the blog posts below, I adopted much of their code with some changes to allow for the use of Ninject for dependency injection.

http://www.tcscblog.com/2012/06/22/entity-framework-generic-repository/

http://www.tugberkugurlu.com/archive/generic-repository-pattern-entity-framework-asp-net-mvc-and-unit-testing-triangle

IRepository.cs

   
public interface IRepository : IDisposable where T : class
    {
        void Add(T entity);
        void Update(T entity, int id);
        T GetById(object key);
        IQueryable Query(Expression> predicate);
        IQueryable GetAll();
        int SaveChanges();
        int SaveChanges(bool validateEntities);
    }

GenericRepository.cs

    
public abstract class GenericRepository : IRepository where T : class
    {
        public abstract void Add(T entity);
        public abstract void Update(T entity, int id);
        public abstract T GetById(object key);
        public abstract IQueryable Query(Expression> predicate);
        public abstract IQueryable GetAll();
        public int SaveChanges()
        {
            return SaveChanges(true);
        }
        public abstract int SaveChanges(bool validateEntities);
        public abstract void Dispose();
    }

One of the issues I ran into was trying to do an update. I kept receiving errors so I posted a question on Stack Overflow

http://stackoverflow.com/questions/12585664/an-object-with-the-same-key-already-exists-in-the-objectstatemanager-the-object

and came up with the following hack. If someone has a better way, please let me know.

DbContextRepository.cs

 public class DbContextRepository : GenericRepository
        where T : class
    {
        protected DbContext Context;
        protected DbSet DbSet;

        public DbContextRepository(DbContext context)
        {
            if (context == null)
                throw new ArgumentException("context");

            Context = context;
            DbSet = Context.Set();
        }

        public override void Add(T entity)
        {
            if (entity == null)
                throw new ArgumentException("Cannot add a null entity.");

            DbSet.Add(entity);
        }

        public override void Update(T entity, int id)
        {
            if (entity == null)
                throw new ArgumentException("Cannot update a null entity.");

            var entry = Context.Entry(entity);

            if (entry.State == EntityState.Detached)
            {
                var attachedEntity = DbSet.Find(id); // Need to have access to key

                if (attachedEntity != null)
                {
                    var attachedEntry = Context.Entry(attachedEntity);
                    attachedEntry.CurrentValues.SetValues(entity);
                }
                else
                {
                    entry.State = EntityState.Modified; // This should attach entity
                }
            }
        }

        public override T GetById(object key)
        {
            return DbSet.Find(key);
        }

        public override IQueryable Query(Expression> predicate)
        {
            return DbSet.Where(predicate);
        }

        public override IQueryable GetAll()
        {
            return Context.Set();
        }

        public override int SaveChanges(bool validateEntities)
        {
            Context.Configuration.ValidateOnSaveEnabled = validateEntities;
            return Context.SaveChanges();
        }

        #region IDisposable implementation

        public override void Dispose()
        {
            if (Context != null)
            {
                Context.Dispose();
                GC.SuppressFinalize(this);
            }
        }

        #endregion IDisposable implementation
    }


At this point I am able to start creating individual repositories that are needed and add a Unit of Work.  Stay tuned for the next installment in my path to creating a Repository Pattern against EF5.

© Geeks with Blogs or respective owner