Should I be using a Generic Repository with Entity Framework 5?

Lando picture Lando · Jul 17, 2013 · Viewed 8.3k times · Source

I'm currently using Entity Framework with a Generic Repository and Unit Of Work Pattern. My Model is similar to the one described in this article

I've used Generic Repositories in the past and really enjoyed the global functionality it can provide. However, it seems I'm running into more problems every single day when it comes to using it with Entity Framework. These problems seem to arise even more when it comes to handling Parent/Children/Junction relationships.

Using a Generic Repository with EF is starting to leave a bad taste in my mouth, and I'm beginning to think that using a Generic Repository with EF is the wrong approach.

Could someone please help steer me in the right direction?

Answer

Gabriel Vonlanten C. Lopes picture Gabriel Vonlanten C. Lopes · Aug 22, 2013

The approach of this article is really something that can be become a pain, because you already have a generic repository and a generic IUnitOfWork in EF and creating the specific repository for each type just removes the benefit of the generic!

I am posting here a sample of how i have a generic Repository and my IUnitOfWork, with this you can have a very nice repository!

public interface IUnitOfWork : IDisposable
{
    void Save();
    void Save(SaveOptions saveOptions);
}

public interface IRepository<TEntity> : IDisposable where TEntity : class
{
    IUnitOfWork Session { get; }
    IList<TEntity> GetAll();
    IList<TEntity> GetAll(Expression<Func<TEntity, bool>> predicate);
    bool Add(TEntity entity);
    bool Delete(TEntity entity);
    bool Update(TEntity entity);
    bool IsValid(TEntity entity);
}

And the implementation something like:

public class Repository : Component, IRepository
{

    protected DbContext session;

    public virtual IUnitOfWork Session
    {
        get
        {
            if (session == null)
                throw new InvalidOperationException("A session IUnitOfWork do repositório não está instanciada.");
            return (session as IUnitOfWork);
        }
    }

    public virtual DbContext Context
    {
        get
        {
            return session;
        }
    }

    public Repository(IUnitOfWork instance)
    {
        SetSession(instance);
    }

    public IList<TEntity> GetAll<TEntity>() where TEntity : class
    {
        return session.Set<TEntity>().ToList();
    }

    public IList<TEntity> GetAll<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : class
    {
        return session.Set<TEntity>().Where(predicate).ToList();
    }

    public bool Add<TEntity>(TEntity entity) where TEntity : class
    {
        if (!IsValid(entity))
            return false;
        try
        {
            session.Set(typeof(TEntity)).Add(entity);
            return session.Entry(entity).GetValidationResult().IsValid;
        }
        catch (Exception ex)
        {
            if (ex.InnerException != null)
                throw new Exception(ex.InnerException.Message, ex);
            throw new Exception(ex.Message, ex);
        }
    }

    public bool Delete<TEntity>(TEntity entity) where TEntity : class
    {
        if (!IsValid(entity))
            return false;
        try
        {
            session.Set(typeof(TEntity)).Remove(entity);
            return session.Entry(entity).GetValidationResult().IsValid;
        }
        catch (Exception ex)
        {
            if (ex.InnerException != null)
                throw new Exception(ex.InnerException.Message, ex);
            throw new Exception(ex.Message, ex);
        }
    }

    public bool Update<TEntity>(TEntity entity) where TEntity : class
    {
        if (!IsValid(entity))
            return false;
        try
        {
            session.Set(typeof(TEntity)).Attach(entity);
            session.Entry(entity).State = EntityState.Modified;
            return session.Entry(entity).GetValidationResult().IsValid;
        }
        catch (Exception ex)
        {
            if (ex.InnerException != null)
                throw new Exception(ex.InnerException.Message, ex);
            throw new Exception(ex.Message, ex);
        }
    }

    public virtual bool IsValid<TEntity>(TEntity value) where TEntity : class
    {
        if (value == null)
            throw new ArgumentNullException("A entidade não pode ser nula.");
        return true;
    }

    public void SetSession(IUnitOfWork session)
    {
        SetUnitOfWork(session);
    }

    protected internal void SetUnitOfWork(IUnitOfWork session)
    {
        if (!(session is DbContext))
            throw new ArgumentException("A instância IUnitOfWork deve um DbContext.");
        SetDbContext(session as DbContext);
    }

    protected internal void SetDbContext(DbContext session)
    {
        if (session == null)
            throw new ArgumentNullException("DbContext: instance");
        if (!(session is IUnitOfWork))
            throw new ArgumentException("A instância DbContext deve implementar a interface IUnitOfWork.");
        this.session = session;
    }

}