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

Asked

Viewed 5,287 times

12

I want to make an implementation of the standard Repository where I will be using the Entityframework and have the following:

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 not to need to be replicated in all other classes Repository. Implementation of IDisposable:

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 be able to implement my default classes Repository:

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’re not allowed to do it that way.
Follow error message:

The type 'CS.domain.Representative' cannot be used as type Parameter’T' in the Generic type or method 'CS.Repository.Customrepository'. There is no implicit Reference Conversion from 'CS.domain.Representative' to 'System.Idisposable'.

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

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

The type 'CS.domain.Representative' cannot be used as type Parameter’T' in the Generic type or method 'CS.Repository.Customrepository'. There is no implicit Version from 'CS.domain.Representative' to 'CS.Repository.Irepository'.

Turkeys:

  1. I’m modeling the pattern wrong?
  2. There is a way to solve the first mistake without having to go rogue and without having to make my domain classes inherit from IDisposable?
  3. How to solve the second error?

2 answers

11

Repository layer

The class Abstract Respository is the place where the standard 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 its 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

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

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

Instilling layer

Repository<Album> RepAlbum = new RepositoryAlbum();
  • Vlw @Crood, is one of the layers that I use in my systems, has several but, this is very practical.

  • 2

    +1. I liked the scheme of having Expressions in the selection methods. I will incorporate these prototypes into my code, including.

  • 2

    In this case, New() is a constraint where it requires a constructor without a parameter. Microsoft Website Explanation: The Type argument must have a constructor without public parameters. When used in conjunction with other restrictions, the new() restriction must be last specified. @Crood

  • 1

    Okay, @Gypsy Gypsy!

  • 2

    Congratulations @Harrypotter, very interesting!

  • Not at all @Tiagopsilva...

Show 1 more comment

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 this does not validate the use of the practice in any application that is.


I’m modeling the pattern wrong?

No, that’s correct. Just a few tweaks left.

There is a way to solve the first mistake without having to go rogue and without having to make my domain classes inherit from Idisposable?

Yes, see below.

How to solve the second error?

Change:

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

To:

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

Browser other questions tagged

You are not signed in. Login or sign up in order to post.