在我的存储库合同的规定期间,我开始怀疑任何Repository
的基本合同:
如果使用未存储更改的实体调用Update
会发生什么?
Repository
的客户,如果我想存储更改,我只会致电Update
。如果没有变化,我会假设我的过程中出现了问题,所以我想知道这个事实。所以我要说:未提交的更改是Update
方法的先决条件。
如果不满足此前提条件,则需要抛出Exception
。
Repository
对改变无动于衷。 Update
方法只是确保给定实体保持现状。 如果有任何变更,则不是Repository's
业务。所以没有异常。就个人而言,我倾向于查看1,因为术语Update
本身表明发生了变化。
您对此主题有何看法?
PS:我们假设(为了这个例子)没有涉及并发性,这当然会导致其他可能的结果。
答案 0 :(得分:2)
如果使用未存储更改的实体调用Update,会发生什么?
我认为你希望这是一个无操作。
使用持久性支持的存储库looks something like
的常用模式final Cargo cargo = cargoRepository.find(trackingId);
cargo.assignToRoute(itinerary);
cargoRepository.store(cargo);
此代码位于应用程序组件中;存储库和Cargo聚合根是域模型允许了解的抽象。实现的细节是其他地方。
谜语:如果cargo.assignToRoute
对于当前状态是无操作,会发生什么? 应用程序无法知道这一点,因为它无法访问基础状态。它调用了模型,模型决定不更改任何内容,因此存储库找到了存储中可用的相同状态。
这可能很重要,因为如果您的邮件通过不可靠的传输(如网络)传递给您,您可能会获得相同邮件的两个副本。如果域模型识别出新行程等于旧行程,则无需更改任何内容。
final Cargo cargo = cargoRepository.find(trackingId);
cargo.assignToRoute(itinerary);
cargoRepository.store(cargo);
final Cargo cargo = cargoRepository.find(trackingId);
cargo.assignToRoute(itinerary);
cargoRepository.store(cargo);
在这个流程中引入一个实际提供商业价值的例外吗?还是我们只为自己创造额外的工作?
我们是否真的投入了大量额外的脚手架来检测以下无害的代码在运行时?
final Cargo cargo = cargoRepository.find(trackingId);
cargoRepository.store(cargo);
在这里思考关于机制的一种方式:我们不会调用模型使其做任何事情。我们称之为域模型,因为我们希望满足特定的post condition。如果模型已经满足该帖子条件,则无需进行任何更改。
这种模式是典型的idempotent receivers;例如,HTTP PUT方法保留给承诺idempotent semantics的操作。
(更确切地说,你提出一个precondition - 调用者确保两个状态不同 - 调用方法必须满足。但在这种情况下,前提条件是幻像;方法可以满足后置条件,它也不会选择。)
答案 1 :(得分:1)
如果您完全确定未提交的更改是一个先决条件,那么如果未满足该前提条件,您有理由抛出异常。 如果这是一个先决条件,则在可能存在更改或可能存在更改的情况下,您将排除非异常调用更新。如果那就是你想要的那么就好了。
然而,正如你在暗示你的观点2时,它并不是真正做出任何例外的存储库。
在您真正期望更改的情况下,您可以考虑单独检查更新前是否存在任何未提交的更改。
这非常类似于在删除之前文件删除时是否应该抛出文件删除的问题。在某些用例中,我真的希望该文件存在,所以如果它没有,那将是例外,但是另一个用例是我想确保文件不存在的地方,但我不知道(或关心)它是否存在。在这种情况下,如果我认为发布条件“调用删除后指定的文件不存在”,那么(除非该文件存在且不可删除)已经满足该文件是否存在之前是否存在。
更新后置条件是在调用后没有未提交的更改,这对于成功更新和无更新案例都是符合的。
在满足后置条件的这些非例外情况下必须捕获异常是令人讨厌的。如果有一个选项或不同的方法可以区分前提条件应该或不应用的情况,代码的意图会更清楚,这可能比单独检查前提条件更有效/更容易。
答案 2 :(得分:1)
不要在您的Repository界面中包含Update
。
存储库是内存中集合的错觉(在此处引用内存中的蓝皮书)。 <{1}}在集合语义中不存在。
相反,请在您的工作单元实施中处理更改跟踪。大多数ORM都有优化的内置变更跟踪功能,您可以方便地将其用于此目的。