【发布时间】:2013-08-22 21:42:09
【问题描述】:
我的问题很简单——在普通的 DDD 域中,对象不应该暴露给表示层(除了有些人更喜欢它——我相信裸对象是怎么称呼的)。但是 CQRS + ES 呢?写入被委托给封装的算法(Events + Sagas),它使用我相信的存储库,然后更新调用它的对象(使用更改的字段/字段)。所以有一些事务逻辑和任何与一致性强制相关的东西......我说的对吗?
【问题讨论】:
标签: dns domain-driven-design cqrs
我的问题很简单——在普通的 DDD 域中,对象不应该暴露给表示层(除了有些人更喜欢它——我相信裸对象是怎么称呼的)。但是 CQRS + ES 呢?写入被委托给封装的算法(Events + Sagas),它使用我相信的存储库,然后更新调用它的对象(使用更改的字段/字段)。所以有一些事务逻辑和任何与一致性强制相关的东西......我说的对吗?
【问题讨论】:
标签: dns domain-driven-design cqrs
命令和查询位于您的域之上。您的表示层与该层对话。
来自我的earlier blogpost:
命令通过明确的方式帮助您支持无处不在的语言 在系统边界捕获用户意图 - 思考使用 案例。您可以将它们视为正在发送到您的 领域。在这方面,它们还可以作为您域的一层 - 内外脱钩,让你逐渐 在内部引入概念,而不破坏外部。这 命令执行器为您提供了一个很好的管道,您可以利用它 集中安全性、性能指标、日志记录、会话 管理等等。
命令代表一个用例。
public class WithdrawMoneyCommand
{
public WithDrawMoneyCommand(string account, decimal amount)
{
// Guard and assign here..
}
public string Account { get; private set; }
public decimal Amount { get; private set; }
}
命令由命令处理程序执行。这是您对聚合进行操作的地方。无论是调用方法和更改状态,还是播放和记录新事件。事务边界位于命令处理程序级别。
public class WithdrawMoneyCommandHandler : IHandle<WithdrawMoneyCommand>
{
public void Handle(WithdrawMoneyCommand command)
{
// Get your account here, and do something with it..
}
}
这是写入端。
在阅读方面,有人向您发送查询,您回复它。就这么简单。
public class AccountBalanceReadModel
{
public string AccountNumber { get; set; }
public decimal Value { get; set; }
}
读取模型可以动态组合查询一个或多个聚合。
public class AccountBalanceQuery
{
public string AccountNumber { get; set; }
}
public class AccountReads : IHandle<AccountBalanceQuery, AccountBalanceReadModel>
{
public AccountBalanceReadModel Handle(AccountBalanceQuery query)
{
// Do query or queries and assemble an AccountBalanceReadModel
}
}
或者(这就是事件发挥作用的地方)读取模型已经可以是您想要的格式,因为它是通过处理事件(由聚合引发)创建的。
public class AccountReads : IHandle<AccountBalanceQuery, AccountBalanceReadModel>
{
public AccountBalanceReadModel Handle(AccountBalanceQuery query)
{
// Do simple query because your read model is already there in the way you like it
}
}
回顾如何使用事件创建读取模型,您将有一些东西处理您的事件并创建读取模型。
public class AcocuntBalanceReadModelDenormalizer : IHandle<AmountWithdrawn>
{
public void Handle(AmountWithdrawn @event)
{
// Update your specialized read model here (AccountBalanceReadModel)
}
}
请注意,事件通常以最终一致的方式处理。这样做的好处是系统的性能和稳定性。
【讨论】: