Sample example of Generic Repository in .NET? Why and how?

Creating some kind of abstraction over the database is almost mandatory when talking about a real project.
In general when talking about web applications the interactions to the database are down to :
  • Create
  • Read
  • Updated
  • Delete
Or so called CRUD operations.
If we decide not to create repositories and use the database context directly it might turns out that we are not fallowing the best OOP practices, because on each database operation we would be doing a couple of repeations in the code. For small applications this might be accepted, but if the applications tend to grow it's highly recommended to use some implementation of the famous Repository pattern. There are a few ways that we can step into:
  • Create separate class (repository) for each database table
  • Create generic repository

The first approach is not our topic now, so i just gonna mention that is it perfectly okay to use it if you want. It gives more freedom and Entity specific actions, but that comes with a price of a lot more source code. More specifically you would have as much repositories as the entities of your database. And they can be a lot. This is why personally I prefer not to use it in this basic form and in this blog post as you already know we will stop our attention to the sample implementation of generic repository pattern.

Left start with some source code of the generic repository interface: (I presume that you are familiarized with the 'Extedned database concept' through generic base model. If you are not you can check it out here
    public interface IDbRepository<T> : IDbRepository<T, int>
        where T : BaseModel<int>
    {
    }

    public interface IDbRepository<T, in TKey>
        where T : BaseModel<TKey>
    {
        IQueryable All();

        IQueryable All(string[] includes);

        IQueryable AllWithDeleted();

        T GetById(TKey id);

        void Add(T entity);

        void Delete(T entity);

        void HardDelete(T entity);

        void Save();
    }

The bottom interface is absolutely generic and can be used with any 'BaseModel' class, which has any type of it's Id, by any i mean string or some numerical type.