Having a repository dependent on another repository

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?

Answers


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.


In this case you should make use of the event dispatcher pattern.

After the delete operation on RepoA you can dispatch an event like:

dispatch repositoryA.deleted(RecordA)

that will hold the information of the deleted record.

An vent listern then will subscribe on such event and, having Repository B as dependence will then invoke a delete.

Let's use B as the entity name, the listener declaration should sound like:

Listen RepositoryA.delete and invoke onDelete(Event)

With this approach you have realized a loose coupling between repoA and repoB (enforcing the Open/Close principle - on the close side-) so repoA have now (again)

regards.


Need Your Help

Xcode "Cannot parse contents of Info.plist"

xcode compiler-errors plist

I just hit a brick wall with xCode not wanting to parse my Info.plist file. I've replaced the file several times with older (identical) versions of the file that I had previously backed up, and I'm...

FileStream StreamReader problem in C#

c#

I'm testing how the classes FileStream and StreamReader work togheter. Via a Console application.