Наличие репозитория, зависящего от другого репозитория

Недавно я потратил время на изучение принципов SOLID и решил посмотреть, как сравнивается база кода, с которой я работаю.

В нашем коде есть репозиторий (репозиторий A). Когда запись должна быть удалена из репозитория A, нам также необходимо удалить связанную запись из репозитория B. Поэтому исходный кодер создал зависимость от конкретной реализации репозитория B. Метод в репозитории A находится в транзакции и удаляет запись из репозитория A, а затем вызывает метод в репозитории B для удаления связанных данных.

Мое понимание принципа S состоит в том, что каждый объект должен иметь только одну причину для изменения, но для моего репозитория A есть 2 причины для изменения? Или я не в курсе?

Ответ 1

Репозиторий должен иметь единую ответственность - сохраняйте один вид объекта. Например. сотрудники. Если вам нужно удалить некоторые связанные записи из другого репозитория, это выглядит как бизнес-логика. Например.

Когда сотрудник уволен, мы должны удалить его журнал работы

И обычное место для бизнес-логики - это службы домена. Эта служба будет иметь как репозитории, так и всю работу:

staffService.Fire(employee)

Реализация будет выглядеть как

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();
        }
    }
}

Итак, основные рекомендации

  • попытайтесь сохранить свою бизнес-логику в одном месте, не распространяйте ее часть на пользовательский интерфейс, часть его на хранилища, часть на базу данных (иногда из-за проблем с производительностью вы должны делать некоторую логику на стороне базы данных, но это исключение)
  • никогда не позволяйте репозиториям ссылаться на другие репозитории, репозиторий - очень низкоуровневый компонент вашего приложения с очень простыми обязанностями.

Вы можете задаться вопросом, что делать, если у вас есть сотрудник, и у него есть вложенный объект, который хранится в другой таблице базы данных. Если вы используете этот объект отдельно от сотрудника, то все как указано выше - вы должны иметь отдельный репозиторий и некоторый другой объект (услугу), который управляет обоими репозиториями. Но если вы не используете этот вложенный объект отдельно от сотрудника, тогда сотрудник является агрегированным корнем, и у вас должен быть только репозиторий сотрудников, который будет запрашивать обе таблицы внутри.

Ответ 2

В этом случае вы должны использовать шаблон диспетчер событий.

После операции удаления в RepoA вы можете отправить событие, например:

dispatch repositoryA.deleted(RecordA)

который будет хранить информацию о удаленной записи.

Затем вентиляционное отверстие будет подписано на таком событии и, имея в качестве репозитория B зависимость, затем вызовет удаление.

Позвольте использовать B как имя сущности, объявление слушателя должно звучать так:

Listen RepositoryA.delete and invoke onDelete(Event)

При таком подходе вы поняли, что связь между repoA и repoB (соблюдение принципа Open/Close - на закрытой стороне)) repoA теперь (снова)

С уважением.