Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/reporting-services/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Domain driven design 如何处理DDD中的故障?_Domain Driven Design - Fatal编程技术网

Domain driven design 如何处理DDD中的故障?

Domain driven design 如何处理DDD中的故障?,domain-driven-design,Domain Driven Design,当我的域中发生“某些内容”更改时,我需要在本地驱动器上创建一个文件夹。因此,以DDD方式,我需要引发一个事件,而不是让我的域创建文件夹 我的问题是,如果我的事件失败(即文件夹创建失败),该怎么办 我是否必须重新发出另一个命令来撤消我认为称为补偿命令的第一个更改 另外,如果补偿命令失败怎么办?现在我有一个域更改,但文件夹不存在。如果文件系统文件夹对您的域至关重要,我会将文件夹创建作为域服务。这样,您就可以让实体处理所有业务规则和逻辑,如果创建文件夹失败,您的域就不会处于无效状态 将服务作为参数传递

当我的域中发生“某些内容”更改时,我需要在本地驱动器上创建一个文件夹。因此,以DDD方式,我需要引发一个事件,而不是让我的域创建文件夹

我的问题是,如果我的事件失败(即文件夹创建失败),该怎么办

我是否必须重新发出另一个命令来撤消我认为称为补偿命令的第一个更改


另外,如果补偿命令失败怎么办?现在我有一个域更改,但文件夹不存在。

如果文件系统文件夹对您的域至关重要,我会将文件夹创建作为域服务。这样,您就可以让实体处理所有业务规则和逻辑,如果创建文件夹失败,您的域就不会处于无效状态

将服务作为参数传递给处理逻辑的方法(双重分派模式)

文件夹服务示例

IFolderService
{
    CreateFolder(string path);
}
实体示例

class MyEntity
{
    public void DoWork(IFolderService folderService, ...)
    {
        folderService.CreateFolder(...);

        // do work.
    }
}

工作完成后,您可以引发域事件来通知子系统。

您描述建议解决方案的方式实际上不是DDD;更多的是CQR(即事件和补偿命令),我认为这可能使情况过于复杂

您是否真的需要对该场景采用CQRS方法,该方法适用于异步操作?与中一样,在单独事务中创建的文件夹与调用和持久化的业务逻辑相比有哪些优势?当引发查询服务处理的事件时,这种方法有很好的理由,因为查询服务可能位于单独的物理机器上,因此需要RPC。此外,事件可能需要更新许多非标准化表格。因此,为了提高性能,这个过程使用异步事件模型是有意义的。但是对于创建一个本地文件夹,我不确定它是否可以

可能的办法

public class ApplicationService : IApplicationService
{
    private readonly IMyAggregateRepository _myAggregateRepository;
    private readonly IFolderCreationService _folderCreationService;

    public ApplicationService(IMyAggregateRepository myAggregateRepository, IFolderCreationService folderCreationService)
    {
        _myAggregateRepository = myAggregateRepository;
        _folderCreationService = folderCreationService;
    }

    public void SomeApplicationServiceMethod(Guid id)
    {
        using (IUnitOfWork unitOfWork = UnitOfWorkFactory.Create())
        {
            MyAggregate aggregate = _myAggregateRepository.GetById(id);

            aggregate.SomeMethod();

            _myAggregateRepository.Save(aggregate);

            _folderCreationService.CreateFolder();
        }
    }
}
在这里,只有当工作单元的using语句中的所有代码都完成且没有错误时,更改才会提交到数据库

请注意,调用文件夹服务的不是域服务或域实体。。。这是应用服务。我更喜欢让域服务专注于纯域逻辑。应用程序服务的工作是协调对域、数据库和任何其他基础结构服务(如此文件夹服务)的客户端调用

如果您认为有充分的理由使用事件模型,那么您所说的是正确的。如果在事件处理程序中创建文件夹失败,则必须发出补偿命令。您需要确保此处理程序不会因设计而失败(我的意思是,所讨论的实体始终处于可以执行此补偿命令的状态;并且状态已恢复)。拥有覆盖所有场景的良好单元测试将有所帮助。如果设计中存在允许此补偿命令失败的缺陷,我猜您必须通过发送电子邮件/失败通知来求助于手动干预


另外,虽然不是问题的重点,但我还是建议不要创建物理文件夹,除非有充分的理由。根据我的经验,这只会让部署/机器升级和其他事情感到头痛。显然,我不知道您这样做的原因,但我真的建议您使用文档存储/数据库来存储您需要存储的任何内容。

您是否必须使其成为事件驱动的?域代码可以调用服务facade(它有一个使用文件系统的实现)吗?然后在失败时抛出一个异常,域代码将处理该异常。感谢David的回复。我可以,但我正在尝试使用DDD方式来处理事件。此外,如果有其他子系统需要通知,那么使用DDD/事件驱动方法,为它们创建事件处理程序应该比处理逻辑的域更容易。David,非常感谢您在这个精彩的回复中花费的时间和精力。在过去的几个月里,我一直在关注CQR,我想我开始将其视为所有事物的架构模式,而不是特定子域的架构模式:)。不幸的是,我正在迁移一个现有的应用程序,所以我们只能使用文件夹,但再次感谢您的建议。