DEV Community

Cover image for .Net Generic Repository Pattern
fullstackcodr
fullstackcodr

Posted on

.Net Generic Repository Pattern

Disclaimer: In this article I provide demo code implementing the Generic Repository Pattern via .Net6 and C#. This is a high overview and not a step by step guide on how to start the project from scratch. I don't expect everyone to agree with the statements below since there are many different ways to implement this Pattern. Finally, English is not my first language, so my apologies for any mistakes.

The Generic Repository Pattern is a wide used way to keep a neat codebase on the Data Access Layer, keeping commonly used CRUD functionality grouped together, giving the ability to make it reusable among the different entity types.

The core concept of the Generic Repository Pattern is that regardless the passed-in data type, the CRUD functionality will adapt to it and will operate the same way. To achieve this, we make use of C# Generics feature.

A Base Generic Repository (async) interface would like this:

    public interface IGenericRepository<T>
    {
        Task<IEnumerable<T>> AllAsync();
        Task<T> GetByIdAsync(string id);
        Task<T> CreateAsync(T entity);
        Task<T> UpdateAsync(T entity);
        Task<string> DeleteAsync(string id);
    }
Enter fullscreen mode Exit fullscreen mode

"T" represents the generic type, it could be understood as a "placeholder" for the different data types.

The implementation of the above interface, using Entity Framework, would like this:

    public class GenericRepository<T>: IGenericRepository<T> where T: BaseEntity
    {

        protected readonly DatabaseContext _context;

        public GenericRepository(DatabaseContext context)
        {
            _context = context;
        }

        public async Task<IEnumerable<T>> AllAsync()
        => await _context.Set<T>().ToListAsync();

        public async Task<T> CreateAsync(T entity)
        {
            entity.Id = Guid.NewGuid().ToString();
            entity.DateUpdated = DateTime.Now;

            await _context.AddAsync(entity);
            await _context.SaveChangesAsync();

            return entity;
        }

        public async Task<string> DeleteAsync(string id)
        {
            var entity = await _context.Set<T>().FindAsync(id);
            _context.Set<T>().Remove(entity);
            await _context.SaveChangesAsync();

            return id;
        }

        public async Task<T> GetByIdAsync(string id)
        => await _context.Set<T>().FirstOrDefaultAsync(x => x.Id == id);

        public async Task<T> UpdateAsync(T entity)
        {
            entity.DateUpdated = DateTime.Now;

            _context.Set<T>().Update(entity);
            await _context.SaveChangesAsync();

            return entity;
        }
    }
Enter fullscreen mode Exit fullscreen mode

As mentioned above, the aim of the base repository is to be shared between other repositories, in order to make use of the already implemented functionality. An example of usage in an individual feature repository interface:

    public interface IVehicleRepository : IGenericRepository<Vehicle>
    {
    }
Enter fullscreen mode Exit fullscreen mode

The above IVehicleRepository inherits the functionality of the IGenericRepository, passing the Vehicle entity to it. In other words, IVehicleRepository is informs the IGenericRepository that it is going to use the CRUD methods against the Vehicle object. And down to the exact feature repository implementation now:

    public class VehicleRepository : GenericRepository<Vehicle>, IVehicleRepository
    {
        protected readonly DatabaseContext _context;

        public VehicleRepository(DatabaseContext context) : base(context)
        {
            _context = context;
        }
    }
Enter fullscreen mode Exit fullscreen mode

The full implementation of the above code can be found here In this demo project I make use of some of the commonly used techniques, features and tools, including: Generics, DI, Async, Entity Framework (InMemory Database), Automapper, XUnit, FluentAssertation, Moq

If you would like to support this effort to provide tutorials and demo code, please like us on Facebook or even ☕ Buy Me A Coffee

Discussion (0)