Having a repository dependent on another repository

MrGrumpy picture MrGrumpy · May 8, 2015 · Viewed 11.8k times · Source

I've recently been spending time reading up on SOLID principles and decided to seeing how the code base I work with compares.

In some of our code there is a repository (repository A). When a record is to be deleted from the repository A, we also need to delete an associated record from repository B. The original coder has therefore created a dependency to a concrete implementation of repository B. The method in repository A is within a transaction and deletes the record from repository A and then calls the method on repository B to delete the associated data.

My understanding of the S principle is that each object should have only 1 reason to change, but to my repository A has 2 reasons to change? Or am I way off the mark?

Answer

Sergey Berezovskiy picture Sergey Berezovskiy · May 8, 2015

Repository should have single responsibility - persist one kind of entity. E.g. employees. If you have to delete some associated records from other repository, it looks like business logic. E.g.

When employee is fired we should remove his work log

And usual place for business logic is a domain services. This service will have both repositories and do all the job:

staffService.Fire(employee)

Implementation will look like

public class StaffService
{
    private IEmployeeRepository employeeRepository;
    private IWorkLogRepository workLogRepository;
    private IUnitOfWorkFactory uowFactory;

    // inject dependencies

    public void Fire(Employee employee)
    {
        using(var uow = uowFactory.SartNew())
        {
            workLogRepository.DeleteByEmployee(employee.Id);
            employeeRepository.Delete(employee.Id);
            uow.Commit();
        }
    }
}

So, basic advises

  • try to keep your business logic in one place, do not spread part of it to UI, part of it to repositories, part to database (sometimes due to performance issues you have to do some logic on database side, but thats an exception)
  • never let repositories reference other repositories, repository is a very low-level component of your application with very simple responsibilities

You may wonder what to do if you have employee and it has some nested object which is stored in different database table. If you use that object separately from employee, then everything is as above - you should have separate repository, and some other object (service) which manipulates both repositories. But if you don't use that nested object separately from employee, then employee is an Aggregate Root and you should have only employee repository, which will query both tables inside.