【问题标题】:DDD use event or service?DDD 使用事件还是服务?
【发布时间】:2019-11-12 05:33:42
【问题描述】:

您好,我是 ddd 设计的新手,正在尝试使用这种在 C# 中工作的模式开发我的第一个应用程序

在我的应用程序中,我有一个包含子实体资产的聚合合同,当添加或结算资产时,我应该在另一个聚合帐户中执行会计操作并确保它在业务逻辑中。

我是否应该创建一个域服务来确保合约资产中的每个操作都会引发一个帐户操作,并在应用层调用该服务发送一个帐户实体的集合。或者我应该将存储库注入此服务加载帐户列表并将更改保存在帐户和操作列表中。

或者甚至让资产实体中的方法引发一个强制帐户更改的事件。如果这是正确的方法,事件句柄应该在域或应用程序中?如果在域中,帐户实体中的处理程序是否应该通过注入的存储库执行更改?

我有点困惑

【问题讨论】:

标签: c# domain-driven-design onion-architecture


【解决方案1】:

通常这类问题可以使用事件优雅地解决,并关注每个事务的一个聚合。

假设您的用例是将资产添加到合同中。

您将拥有一个带有 ContractRepository 的应用程序服务,该服务将检索该合同,并且将在该合同上调用一个方法 addAsset

当您将资产添加到您的合同聚合时,此聚合将记录一个域事件,例如 AssetAdded,以及有关该操作的所有相关信息。然后您的应用程序服务会将更新后的 Contract 保存在数据库中,然后它将事件发布到异步总线。此时您可以发送回复。

在您的应用程序中,某些订阅者将收到有关该事件的通知并会做一些事情。在这种情况下,您可以拥有一个 UpdateAccountOnAssetAdded,它会在内部完成其余的工作。

This article 将帮助您了解这种架构中的一切是如何组织的。

祝你好运!

【讨论】:

  • 感谢 rastafermo 的回答,这是我为这个问题实现的第一个解决方案,但领域专家多次表示,每次添加或结算资产时都应该进行账户操作,这是这个域的黄金法则,所以如果,我认为应用程序不应该负责执行这个操作,而是它自己的域。问题开始是因为帐户是一个聚合(客户也可以修改帐户的状态),所以如果没有在域服务或加载帐户的方法中注入存储库,我可以在域内制定此规则吗?
  • 但是如果我以聚合方法或服务注入存储库以加载和保存帐户,我将使域意识到持久性。我真的不知道这里最优雅的解决方案是什么。另一种选择是将所有聚合方法设为内部,并创建一个接收帐户集合和合约的服务,该服务处理两个 AR 中的方法并确保所有必要的操作,然后应用程序调用发送两个 AR 的服务
  • 但我真的不知道什么是最好的选择
  • 忘记在域对象中使用存储库,但是可以拥有一个服务,例如应用程序服务,它使用您提到的那些存储库检索您需要的所有内容,然后将所有内容传递给一个域服务负责应用您的域规则和逻辑。您需要专注于如何分离职责。应用程序服务应该只是您的域的促进者,例如从 DB 中检索聚合,但实际上是您的域对这些聚合执行逻辑。
【解决方案2】:

让我们先回答最后一个问题。事件用于可以异步完成的事情,在这种情况下异步将不起作用。每次保存聚合时,它都应满足所有业务规则,因此您必须同时处理资产和帐户。

应谨慎使用服务。他们在不止一个 AR 上运行,其中没有一个与其他 AR 有强制关系。在您的情况下,Contract 拥有所有其他涉及的实体,因此所有工作都应在 Contract 的方法内完成。如果这需要一个存储库,则将其注入到合约中。

【讨论】:

  • 嗨布拉德感谢您的回答,但在我的情况下,帐户应该是一个单独的聚合,因为还有其他与合同无关的操作。我很可能能够处理聚合合同之外的帐户
  • Account 仍然可以是单独的聚合,同时由合约拥有,而不是聚合根。不同之处在于 AR 不保证其 AR 边界之外的有效性,因此保存有效合同并不一定意味着该帐户也是有效的
  • 谢谢布拉德,我会尝试找到一种方法
  • 在这种情况下还有一个疑问,聚合合约是否会引用其他正确的聚合账户?
  • 所以在 AR 合约中我们有一个行为 public void AddAsset(decimal assetValue, int assetType) { this.Assets.Add(new Asset(assetValue, assetType)); AccountingRules rules = this.IAccountingRulesRepo.GetByAssetID(assetType); Account accountDebit = new Account(rules.DebitAccount); Account accountCredit = new Account(rules.CreditAccount); accountCredit.Credit(assetValue); accountDebit.Debit(assetValue); this.IAccountRepo.Save(accountCredit); this.IAccountRepo.Save(accountDebit); }
猜你喜欢
  • 2019-08-23
  • 2021-03-17
  • 1970-01-01
  • 1970-01-01
  • 2020-07-21
  • 2011-01-23
  • 1970-01-01
  • 1970-01-01
  • 2016-11-15
相关资源
最近更新 更多