Generic Repository Design Pattern

CodeWithHonor
3 min readDec 23, 2022

--

The generic repository design pattern is a way of abstracting data access logic in C#. It is used to provide a common interface for interacting with a data source, such as a database, and can be used to abstract away the details of the specific data access implementation.

Here is an example of a generic repository interface in C#:

public interface IRepository<T> where T : class
{
T GetById(int id);
IEnumerable<T> GetAll();
void Add(T entity);
void Update(T entity);
void Delete(T entity);
}

This interface defines a set of basic CRUD (create, read, update, delete) methods for interacting with a data source. The T type parameter represents the type of entity being stored in the repository.

Here is an example of a concrete implementation of the generic repository interface using Entity Framework:

public class EFRepository<T> : IRepository<T> where T : class
{
private readonly DbContext _context;
private readonly DbSet<T> _dbSet;

public EFRepository(DbContext context)
{
_context = context;
_dbSet = context.Set<T>();
}

public T GetById(int id)
{
return _dbSet.Find(id);
}

public IEnumerable<T> GetAll()
{
return _dbSet.ToList();
}

public void Add(T entity)
{
_dbSet.Add(entity);
}

public void Update(T entity)
{
_context.Entry(entity).State = EntityState.Modified;
}

public void Delete(T entity)
{
_dbSet.Remove(entity);
}
}

In this example, the EFRepository class implements the IRepository interface using Entity Framework. It takes a DbContext instance in its constructor, and uses it to interact with the database using the DbSet class.

The generic repository pattern is a useful way of abstracting data access logic and providing a consistent interface for interacting with a data source. It can help to improve the modularity and testability of code, and make it easier to maintain and extend.

Here are some additional details about the generic repository design pattern:

  1. Repository versus unit of work: The repository pattern is often used in conjunction with the unit of work pattern. The unit of work pattern is a way of tracking changes to multiple objects as a single unit of work, and allows the changes to be committed or rolled back as a single transaction. The repository pattern is responsible for managing the individual objects, while the unit of work pattern is responsible for managing the transaction.
  2. Custom repository methods: In addition to the basic CRUD methods, you can also define custom repository methods that perform more specific tasks. For example, you might define a method that searches for entities based on a specific criteria, or a method that returns a paginated list of entities.
  3. Inversion of control: The generic repository pattern can be implemented using inversion of control (IoC) containers, which are used to manage the creation and injection of dependencies. This allows the repository implementation to be easily swapped out or mocked for testing purposes.
  4. Repository per entity: It is common to create a separate repository for each entity type, rather than having a single repository that can work with any entity type. This allows the repository to be tailored to the specific needs of the entity, and can help to improve the readability and maintainability of the code.
  5. Pros and cons: Like any design pattern, the generic repository pattern has its own set of advantages and disadvantages. Some of the pros of the pattern include the ability to abstract away data access logic, improve modularity and testability, and provide a consistent interface for interacting with a data source. Some of the cons include the need to create additional layers of abstraction, the potential for unnecessary complexity, and the possibility of over-engineering simple solutions.

I hope this informations helps to clarify the generic repository design pattern. Please let me know if you have any further questions.

--

--