T4under4
T4under4

Reputation: 155

How to remove code redundancy in repositories

Currently I have 2 tables in my database. Meals and Tables (it's restaurant managing application). I have created repositories interfaces and their implementation for both tables (Authorized user should be able to add/remove/update meals and tables data when for example new meal appears in menu). The problem is that both of my interfaces have basically the same method which causes code redundancy I believe. These are my interfaces:

public interface IMealsRepository
{
    IEnumerable<Meal> FindAll();
    Meal FindById(int id);
    Meal FindByName(string mealName);
    Meal AddMeal(MealDTO newMeal);
    void RemoveMeal(int id);
    Meal UpdateMeal(Meal meal);
}

public interface ITablesRepository
{
    IEnumerable<Table> FindAll();
    Table FindById(int id);
    Table AddTable(Table newTable);
    void RemoveTable(int id);
    Table UpdateTable(Table table);
}

I tried to make a base repository interface with common methods of FindAll, FindById, Add, Remove, Update but I ran into problem that I'm taking and returning different types e.g. for Add method I either return Table object or Meal object depending on the interface. I tried to go with object approach:

public interface IRepository
{
    IEnumerable<object> FindAll();
    object FindById(int id);
    object Add(object newObject);
    void Remove(int id);
    object Update(object updatedObject);
}

Then I would just IMealsRepository : IRepository and ITablesRepository : IRepository and add additional methods unique for those repositories which is for example searching Meal by name. My meals interface would look like this:

public interface IMealsRepository : IRepository
{
    Meal FindByName(string mealName);
}

I also have Services for those Repositories that are the only one able to access repositories and return those particular types of objects using repositories methods. Is that a good approach or I'm going way too deep in this project regarding interfaces of my repositories?

Upvotes: 1

Views: 138

Answers (2)

benjamin
benjamin

Reputation: 1654

This type of problem can be solved with .NET Generics. Generics allow you to create classes like RepositoryBase<T> and interfaces like IRepository<T>

The "T" is the type of an object you specify in the inheriting class or implementing interface.

Using Generics, you could create an interface like this:

public interface IRepository<T>
{
    IEnumerable<T> FindAll();
    T FindById(int id);
    T Add(T newObject);
    void Remove(int id);
    T Update(T updatedObject);
}

Or a base class like this:

public abstract class RepositoryBase<T, TDto> : IRepository<T>
{
    protected IEnumerable<T> FindAll() { // your implementation logic}
    protected T FindById(int id) { // your implementation logic
    protected T FindByName(string mealName) { // your implementation logic
    protected T AddMeal(TDto newMeal) { // your implementation logic
    protected void RemoveMeal(int id) { // your implementation logic
    protected T UpdateMeal(Meal meal) { // your implementation logic
}

There is lots of information about generics available on the internet but I'm pretty sure Generics is what you want to use in this scenario.

Upvotes: 1

Pankaj Rawat
Pankaj Rawat

Reputation: 4583

You can follow this link to implement Generic/Base Repository (If you are not using Entity Framework/SQL, still this is valid).

Other than Base/Generic repository pattern you need to consider a few things

  1. Use UnitOfWork pattern when you are doing the operation in multiple repositories to maintain transaction.

  2. Don't create repository for each table/domain object. Create a repository only for Aggregate object (example in E-Commerce context is Order not for OrderDetail).

  3. Don't create table/domain-specific repository, If you don't need. If you're doing simple CRUD operation and all type of operation already available in my base repository then you don't need a table-specific repository

    public class AdvertisementService : IAdvertisementService { private readonly IBaseRepository imageRepository;

    public AdvertisementService(
        IBaseRepository<AdvertisementImage> imageRepository)
    {
    
        this.imageRepository = imageRepository;
    }
    

Startup.cs

builder.Services.AddScoped<IBaseRepository<AdvertisementImage>, BaseRepository<AdvertisementImage>>();

In the above example, I didn't create any `AdvertisementImage' repository.

Upvotes: 2

Related Questions