拥有依赖于另一个存储库的存储库

Having a repository dependent on another repository

我最近一直在花时间阅读 SOLID 原则,并决定比较一下我使用的代码库。

在我们的一些代码中有一个存储库(存储库 A)。当要从存储库 A 中删除一条记录时,我们还需要从存储库 B 中删除一条关联的记录。因此,原始编码人员创建了对存储库 B 的具体实现的依赖。存储库 A 中的方法在一个事务中并且从存储库 A 中删除记录,然后调用存储库 B 上的方法删除关联数据。

我对S原则的理解是每个对象应该只有1个原因要改变,但是我的仓库A有2个原因要改变?还是我离题太远了?

存储库应具有单一职责 - 保留一种实体。例如。雇员。如果你必须从其他存储库中删除一些关联的记录,它看起来像业务逻辑。例如。

When employee is fired we should remove his work log

业务逻辑的通常位置是域服务。该服务将拥有两个存储库并完成所有工作:

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

所以,基本建议

  • 尽量将您的业务逻辑放在一个地方,不要将其一部分分散到 UI,一部分分散到存储库,一部分分散到数据库(有时由于性能问题,您必须在数据库端,但那是一个例外)
  • 永远不要让存储库引用其他存储库,存储库是应用程序的一个非常低级的组件,职责非常简单

您可能想知道如果您有员工并且它有一些存储在不同数据库中的嵌套对象,该怎么办 table。如果您与员工分开使用该对象,那么一切都如上 - 您应该有单独的存储库,以及一些其他操作这两个存储库的对象(服务)。但是如果你不使用与员工分开的嵌套对象,那么员工就是一个聚合根,你应该只有员工存储库,它将查询里面的两个 tables。

在这种情况下,您应该使用 event dispatcher 模式。

RepoA 上执行删除操作后,您可以发送如下事件:

dispatch repositoryA.deleted(RecordA)

将保留已删除记录的信息。

然后 vent listern 将订阅此类事件,并且将存储库 B 作为依赖项然后调用删除。

让我们使用 B 作为实体名称,侦听器声明应该听起来像:

Listen RepositoryA.delete and invoke onDelete(Event)

通过这种方法,您实现了 repoArepoB 之间的松散耦合(强制执行 Open/Close 原则 - 在close side-) 所以 repoA 现在(再次)

问候。