CQRS/EventStore:如何检查聚合是否存在?

发布于 2024-12-31 21:09:31 字数 144 浏览 0 评论 0原文

我目前正在使用 J Oliver 的 EventStore,我想知道在执行调用 (GetById(Guid id)) 时如何检查聚合是否存在?

按照 CQRS 的工作原理,我应该查询读取的数据库还是应该以某种方式找出 EventStore 中是否有相应的聚合?

I am currently using J Oliver's EventStore and I want to know how I can check if an aggregate exists when I do my call (GetById(Guid id))?

Following how CQRS works, should I be querying the read database or should I somehow find out if there is a corresponding aggregate in the EventStore?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

我三岁 2025-01-07 21:09:31

目前 EventStore 的工作方式是,如果未找到流,您将创建一个新的流(聚合根)。

检查这一行:
https://github.com /joliver/CommonDomain/blob/master/src/proj/CommonDomain.Persistence.EventStore/EventStoreRepository.cs#L53

在 Store 上调用此方法:
https://github.com/joliver /EventStore/blob/master/src/proj/EventStore.Core/OptimisticEventStore.cs#L45

调用此构造函数:
https://github.com/joliver /EventStore/blob/master/src/proj/EventStore.Core/OptimisticEventStream.cs#L27

效果是,它将使用在持久性中找到的提交来填充流,或者如果没有找到,它将不执行任何操作并返回新的 Stream。

但是,您不必问自己这个问题。在发送命令之前应先对其进行验证。在发送命令之前,使用您的读取模型来验证该命令。

此外,命令和聚合根状态应该足以提供您在域中执行决策的信息。这基本上意味着您必须在发送命令之前确定域状态,以避免域中出现异常。您可以使用读取模型来实现这一点。

更新作为对Mauros评论的回应:

您遇到了并发问题。您也许可以使用偶尔连接的系统中使用的合并方法来解决该问题。您可以做的是将 Stream 修订版本存储在读取模型中,以便您知道您对 AR 的哪个版本进行了操作。然后,当命令被处理时,您就知道您是否正在按照 AR 的旧状态进行操作。

如果 AR 版本高于该命令带来的版本,您可以将该命令视为失败而放弃(悲观并发),也可以尝试合并更改。

这可以通过查看命令中的修订版本直到当前状态所产生的事件来完成。然后调用该命令应该执行的行为并查看该行为创建的事件并比较两个事件集合。如果没有任何冲突的事件,您可以将新创建​​的事件提交到存储。如果存在冲突,可以抛出并发异常。

我认为这是解决此类并发问题的最佳选择。

搜索事件合并以获取更多信息。

The way the EventStore works at the moment, you will create a new Stream (Aggregate root) if the stream is not found.

Check this line:
https://github.com/joliver/CommonDomain/blob/master/src/proj/CommonDomain.Persistence.EventStore/EventStoreRepository.cs#L53

It calls this method on the Store:
https://github.com/joliver/EventStore/blob/master/src/proj/EventStore.Core/OptimisticEventStore.cs#L45

Which calls this constructor:
https://github.com/joliver/EventStore/blob/master/src/proj/EventStore.Core/OptimisticEventStream.cs#L27

The effect is that it will either populate the Stream using Commits that it found in the persistence, or if none are found it will do nothing and return the new Stream.

However, you shouldn't have to ask yourself this question. A Command should be validated before you send it. Use your read models to validate the command before you send it.

Also, the Command together with Aggregate root state should be enough information to perform your decision in the domain. This basically means that you have to be certain of the domain state before you send your commands in order to avoid exceptions in the domain. And you can use the the read model for that.

Update as a response to Mauros comment:

You are having a concurrency issue. You might be able to solve it by using the method used in occasionally connected systems which is merging. What you can do is to store the Stream revision in the read model so that you know which revision of the AR you have acted upon. Then when the command is handled you know if you were acting upon an old state of the AR.

If the AR revision is higher than than the one the command brings you can either discard the command as a failure (pessimistic concurrency), or you can try to merge the changes.

This can be done by looking at the events produced from the revision in the command up until the current state. Then invoke the behavior the command was supposed to do and look at the events created by that behavior and compare the two event collections. If there aren't any conflicting events, you can commit the newly created events to the store. If there are conflicts, you can throw a concurrency exception.

I think that is your best bet to solve this type of concurrency issues.

Search for Event Merging for more info.

强辩 2025-01-07 21:09:31

我猜您实际上指的是 JOliver 的 CommonDomain 项目中的 IRepository.GetById()

当您使用不在事件存储中的聚合根 ID 调用 GetById 时,存储库将为您提供一个新的聚合对象,其中 .Version == 0 且 .Id == Guid.Empty。我刚刚创建了自己的派生存储库,它检测该条件并返回 null:

public override TAggregate GetById<TAggregate>(Guid id, int versionToLoad)
{
    var aggregate = base.GetById<TAggregate>(id, versionToLoad);
    return aggregate.Version > 0 ? aggregate : null;
}

这可能是错误的方法(请参阅 Mikael 的答案),但到目前为止它对我来说工作得很好。

I guess you're actually referring to IRepository.GetById() in JOliver's CommonDomain project?

When you call GetById with an aggregate root id that isn't in the event store, the repository will give you a new aggregate object with .Version == 0 and .Id == Guid.Empty. I just created my own derived repository that detects that condition and returns null instead:

public override TAggregate GetById<TAggregate>(Guid id, int versionToLoad)
{
    var aggregate = base.GetById<TAggregate>(id, versionToLoad);
    return aggregate.Version > 0 ? aggregate : null;
}

That might be the wrong way to go about it (see Mikael's answer) but it's working fine for me so far.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文