更改自: “使用实体框架(和其他 ORM)进行域模型验证。数据库中的一些数据,内存中的一些数据。”
最初我认为用 EF 实现 UoW 是一件容易的事。但事实证明这要棘手得多。
当业务逻辑(无论它位于何处)向存储库请求实体时,它不仅应该在数据库中搜索,还应该在本地缓存中搜索。存储库不应返回实体,以防它在当前 UoW 中被标记为删除,但它仍然存在于存储中。
带来复杂性的是部分图物化。当我们忘记持久性并假装一切都存在于内存中时,毫无疑问:加载一切,根据需要更改它,然后将结果更改写入 db。尽可能简单。
添加更多细节:
身份验证消息处理程序设置主体。
在我的 BL 深处,我需要检查当前经过身份验证的用户是否可以执行该操作。
每个角色都有与之相关的动作。所以我需要找到所有角色的动作并检查用户是否在角色中。但是,有可能在处理请求期间用户已从角色中删除。有关删除(或添加)的信息保存在 UoW 内部,但尚未保存。因此,如果我的检查逻辑只询问 DB,它可以获得与工作流程不一致的答案。
可能我错误地设置了 UoW 的边界,它不应该跨越单独的 BL 操作:
- 从角色中删除用户 - 更改到 DB
- 检查用户角色 - 从 DB 获取状态
尽管 BL 可以在每次写入 DB 时进行嵌套调用。所以我觉得让客户定义UoW的“大小”是可以的。
福勒描述UoF 说:
您可以在每次更改对象模型时更改数据库,但这会导致大量非常小的数据库调用,最终会非常缓慢。此外,它要求您为整个交互打开一个事务,如果您有一个跨越多个请求的业务事务,这是不切实际的。如果您需要跟踪已读取的对象以避免不一致的读取,情况会更糟。
但是行为可能需要一系列对象更改。并且每次更改都必须了解当前状态 - 先前更改后尚未存储在 DB 中的状态。
问题的原始措辞:
我对使用实体框架实现的存储库和工作单元模式有点困惑。
首先,我允许我的模型在 UnitOfWork 的 Commit() 阶段之前处于无效状态。
为什么这是有益的最简单的例子是移动和重命名文件语义。
如果您需要移动file1
到Dir2
并将其重命名为,如果您在事务上具有独立的移动和重命名操作file2
,则没有简单的方法可以做到这一点。在或
中存在命名冲突。Dir1
Dir2
所以我认为允许模型暂时具有无效状态是合理的。
现在我的问题的本质:
我的业务模型有一个规则,要求分析所有相关实体。
我将验证逻辑放在逻辑上包含所有这些项目的父实体中,因此负责施加和检查约束。而且我还想检查唯一性约束。
这听起来有点偏执,但在这种情况下,即使不使用数据库,我也可以通过单元测试轻松检查我的逻辑。
然而,在 EF 开始验证过程“未来”系统的状态由当前上下文(添加、删除、修改项)和未具体化到内存中并保留在 db 中的部分(更不用说并发)定义。(绝对没有将所有实体加载到内存中)。
这需要我的存储库非常详细,以考虑分布式状态的事实。我发现这不是一项微不足道的任务。
我想知道其他人是如何解决这个问题的。可能有更好的方法来解决这个问题。