How to implement the Standard Repository in C # with EF?

11

I want to make an implementation of the Repository pattern where I'll be using EntityFramework and have the following: p>

Interface IRepository :

public interface IRepository<T> where T : class
{
    T GetById(int id);
    IQueryable<T> GetAll(Expression<Func<T, bool>> filter);
    bool Save(T entity);
    bool Delete(int id);
    bool Delete(T entity);
}

Standard class already having some implementations so it does not need to be replicated across all other Repository classes . IDisposable implementation:

public abstract class CustomRepository<T> where T : class, IRepository<T> , IDisposable
{
    protected readonly DataContext context;

    public CustomRepository(DataContext dataContext) {
        this.context = dataContext;
    }

    // Implements of IRepository<T>
    public abstract T GetById(int id);
    public abstract IQueryable<T> GetAll(Expression<Func<T, bool>> filter);
    public abstract bool Save(T entity);
    public abstract bool Delete(int id);
    public abstract bool Delete(T entity);

    // implements of IDisposable
    public void Dispose() {
        if (context != null)
            context.Dispose();
        GC.SuppressFinalize(this);
    }
}

And then I can implement my classes from the Repository pattern:

public class RepresentanteRepository : CustomRepository<Domain.Representante>
{
    public override Domain.Representante GetById(int id) { ... }

    public override IQueryable<Domain.Representante> 
        GetAll(Expression<Func<Domain.Representante, bool>> filter) { ... }

    public override bool Save(Domain.Representante entity) { ... }
    public override bool Delete(int id) { ... }
    public override bool Delete(Domain.Representante entity) { ... }
}

But you are not being allowed to do this. Here is the error message:

  

The type 'CS.Domain.Representant' can not be used as type parameter 'T' in the generic type   or method 'CS.Repository.CustomRepository'. There is no implicit reference conversion   from 'CS.Domain.Representant' to 'System.IDisposable'.

Then I added the inheritance of IDisposable in my class Domain.Representante .

However I am still hindered. I get the following error message:

  

The type 'CS.Domain.Representant' can not be used as type   parameter 'T' in the generic type or method   'CS.Repository.CustomRepository'. There is no implicit reference   conversion from 'CS.Domain.Representante' to   'CS.Repository.IRepository'.

Peruntas:

  • Am I shaping the pattern wrong?
  • Can you solve the first error without having to make a mistake and without having to make my domain classes inherit from IDisposable ?
  • How to resolve the second error?
  • asked by anonymous 16.05.2014 / 21:37

    2 answers

    9

    Using repository on top of Entity Framework is always a bad practice . In this answer, I only solve the generic code problem that the questioner is having, but that does not validate the use of the practice in any application whatsoever.

      

    Am I shaping the pattern wrong?

    No, it's correct. There are only a few adjustments left.

      

    How can I solve the first error without the need for gambiarra and without having to make my domain classes inherit from IDisposable?

    Yes, see below.

      

    How to resolve the second error?

    Switch:

    public abstract class CustomRepository<T> where T : class, IRepository<T> , IDisposable
    { ... }
    

    To:

    public abstract class CustomRepository<T>: IRepository<T>, IDisposable
        where T : class
    { ... }
    
        
    16.05.2014 / 22:06
    11

    Repository Layer

    The class Abstract Respository is the place where the default encoding is done, having implemented the IRepository Interface.

    Interface

    public interface IRepository<T> : IDisposable where T : class, new()
    {
        T Create();
        DbSet<E> Create<E>() where E : class, new();        
        T Insert(T model);
        bool Edit(T model);
        bool Delete(T model);
        bool Delete(Expression<Func<T, bool>> where);
        bool Delete(params object[] Keys);
        T Find(params object[] Keys);
        T Find(Expression<Func<T, bool>> where);
        IQueryable<T> Query();
        IQueryable<T> Query(params Expression<Func<T, object>>[] includes);
        IQueryable<T> QueryFast();
        IQueryable<T> QueryFast(params Expression<Func<T, object>>[] includes);
        DbContext Context { get; }
        DbSet<T> Model { get; }
        Int32 Save();
        Task<Int32> SaveAsync();
    }
    

    Abstract

    DbEntities would be your main context

    public abstract class Repository<T> : IRepository<T> where T : class, new()
    {   
        public Repository()
        {
            this.Context = Activator.CreateInstance<DbEntities>();
            this.Model = this.Context.Set<T>();
        }
        public Repository(DbContext Context)
        {
            this.Context = Context;
            this.Model = this.Context.Set<T>();
        }
        public T Insert(T model)
        {
            this.Model.Add(model);
            this.Save();
            return model;
        }
        public bool Edit(T model)
        {
            bool status = false;
            this.Context.Entry<T>(model).State = EntityState.Modified;
            if (this.Save() > 0)
            {
                status = true;
            }
            return status;
        }
        public bool Delete(T model)
        {
            bool status = false;
            this.Context.Entry<T>(model).State = EntityState.Deleted;
            if (this.Save() > 0)
            {
                status = true;
            }
            return status;
        }
        public bool Delete(System.Linq.Expressions.Expression<Func<T, bool>> where)
        {
            bool status = false;
            T model = this.Model.Where<T>(where).FirstOrDefault<T>();
            if (model != null)
            {
                status = Delete(model);
            }
            return status;
        }
        public bool Delete(params object[] Keys)
        {
            bool status = false;
            T model = this.Model.Find(Keys);
            if (model != null)
            {
                status = Delete(model);
            }
            return status;
        }
        public T Find(params object[] Keys)
        {
            return this.Model.Find(Keys);
        }
        public T Find(System.Linq.Expressions.Expression<Func<T, bool>> where)
        {
            return this.Model.Where<T>(where).FirstOrDefault<T>();
        }
        public IQueryable<T> Query()
        {
            return this.Model;
        }
        public IQueryable<T> Query(params Expression<Func<T, object>>[] includes)
        {
            IQueryable<T> Set = this.Query();
            foreach (var include in includes)
            {
                Set = Set.Include(include);
            }
            return Set;
        }
        public IQueryable<T> QueryFast()
        {
            return this.Model.AsNoTracking<T>();
        }
        public IQueryable<T> QueryFast(params Expression<Func<T, object>>[] includes)
        {       
            IQueryable<T> Set = this.QueryFast();
            foreach (var include in includes)
            {
                Set = Set.Include(include);
            }
            return Set.AsNoTracking();
    
        }
        public T Create()
        {
            return this.Model.Create();
        }
        public DbSet<E> Create<E>()
            where E: class, new()
        {            
            return this.Context.Set<E>();
        }
        public System.Data.Entity.DbContext Context
        {
            get;
            private set;
        }
        public System.Data.Entity.DbSet<T> Model
        {
            get;
            private set;
        }
        public void Dispose()
        {
            if (this.Context != null)
            {
                this.Context.Dispose();
            }
            GC.SuppressFinalize(this);
        }
        public int Save()
        {
            return this.Context.SaveChanges();
        }
        public async System.Threading.Tasks.Task<int> SaveAsync()
        {
            return await this.Context.SaveChangesAsync();
        }
    }
    

    Respository Album

    Note that this is one of Repository , that is, if you have more you need to create classes in this way inheriting from Class Abstract Respository . Example RepositoryNoticia , RepositoryCliente , etc.

    public class RepositoryAlbum : Repository<Album>
    {
        public RepositoryAlbum() { }
        public RepositoryAlbum(DbContext Context) : base(Context) { }   
    }
    

    Instantiating layer

    Repository<Album> RepAlbum = new RepositoryAlbum();
    
        
    16.05.2014 / 22:21