使用存储库模式保存复杂的聚合
我们有一个复杂的聚合(出于保密原因混淆了敏感名称)。
根 R 由 Ms、As、Cs、Ss 的集合组成。女士还收集了其他低级细节。等等
R确实是一个聚合(不公平地建议我们拆分它!)
我们使用延迟加载来检索详细信息。那里没问题。
但我们在如何保存如此复杂的聚合方面遇到了一些困难。
从调用者的角度来看:
r = repository.find(id);
r.Ps.add(factory.createP());
r.Cs[5].updateX(123);
r.Ms.removeAt(5);
repository.save(r);
我们的竞争解决方案是:
脏标志 聚合中的每个实体都有一个脏标志。存储库中的 save() 方法遍历树查找脏对象并保存它们。删除和添加有点棘手 - 特别是延迟加载 - 但可行。
事件侦听器累积更改。 存储库订阅更改并累积事件的侦听器。当调用 save 时,存储库会抓取所有更改事件并将它们写入数据库。
放弃存储库模式。 实现重载的保存方法来单独保存聚合的各个部分。原来的例子将变成:
r = 存储库.find(id); r.Ps.add(factory.createP()); r.Cs[5].updateX(123); r.Ms.removeAt(5); 存储库.save(r.Ps); 存储库.save(r.Cs); repository.save(r.Ms);
(或更糟)
请提出建议!我们应该做什么?
We have a complex aggregate (sensitive names obfuscated for confidentiality reasons).
The root, R, is composed of collections of Ms, As, Cs, Ss. Ms have collections of other low-level details. etc etc
R really is an aggregate (no fair suggesting we split it!)
We use lazy loading to retrieve the details. No problem there.
But we are struggling a little with how to save such a complex aggregate.
From the caller's point of view:
r = repository.find(id);
r.Ps.add(factory.createP());
r.Cs[5].updateX(123);
r.Ms.removeAt(5);
repository.save(r);
Our competing solutions are:
Dirty flags
Each entity in the aggregate in the aggregate has a dirty flag. The save() method in the repository walks the tree looking for dirty objects and saves them. Deletes and adds are a little trickier - especially with lazy-loading - but doable.Event listener accumulates changes.
Repository subscribes a listener to changes and accumulates events. When save is called, the repository grabs all the change events and writes them to the DB.Give up on repository pattern.
Implement overloaded save methods to save the parts of the aggregate separately. The original example would become:r = repository.find(id);
r.Ps.add(factory.createP());
r.Cs[5].updateX(123);
r.Ms.removeAt(5);
repository.save(r.Ps);
repository.save(r.Cs);
repository.save(r.Ms);
(or worse)
Advice please! What should we do?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
解决方案 1(使用脏标志)不合适,因为您最终会导致持久性逻辑泄漏到域模型中。您的领域模型不应该关心持久性:更改了什么,添加了什么,等等。
在吉米·尼尔森(Jimmy Nillson)的书中,我注意到他处理这种情况的方式是,每次要持久保存聚合时,都会更新聚合根,删除其所有子项,然后再次插入每个子项。
这是一个相当容易实施的解决方案,但它有一些影响。例如,每次重新插入子对象时,其 ID 都可能会更改。如果另一个用户同时编辑同一个聚合怎么办?
以前有其他人遇到过这个问题吗?
莫什
Solution 1 (using dirty flags) is not appropriate because you end up with your persistence logic leaking into your Domain Model. Your Domain Model shouldn't care about the persistence: what is changed, what is added, so on.
In Jimmy Nillson's book I noticed the way he handled this scenario was that everytime the aggregate was to be persisted, the aggregate root was updated, all of its children were deleted, and then each were inserted again.
This is a fairly easy solution to implement, however it has some implications. For example, everytime you re-insert a child object, its ID may be changed. What if another user is editing the same aggregate at the same time?
Has anyone else come across this issue before?
Mosh
因此,如果您不想使用 ORM,则必须构建自己的 ORM。您可以将其命名为存储库,但实际上这将是一个 ORM。
解决方案3违背了存储库的理念,所以我建议不要使用它。在从数据库加载时保存聚合的工作单元状态,然后在提交期间将其与当前状态进行比较怎么样?您可以摆脱所有脏标记内容,但代价是在内存中存储一些额外的数据。
So, if you don't wan't to use an ORM, you have to build your own. You can name it repository, but in fact this would be an ORM.
Solution 3 is against the idea of repository, so I would advice not to use it. How about saving in the Unit of Work state of the aggregate in the moment of loading from database and later, during commit, comparing it to the current state? You could get rid of all the dirty-marking stuff at the cost of storing some additional data in memory.