在我们的项目中,我们正在尝试应用限界上下文思想,但我们面临着一种明显的性能问题。例如,我们有不同的类(在不同的上下文中)来表示系统中的用户:Person
在我们的核心域上下文和User
安全上下文中。因此,我们为每个聚合有两个不同的存储库,但它们使用 DB 中的同一个表,有时访问相同的数据。
在这种情况下,是否有最小化数据库往返的通用解决方案?是否有处理它的 ORM,或者我们应该自己编写一些缓存系统?
upd:数据库来自旧版应用程序,我们必须“按原样”使用它
在我们的项目中,我们正在尝试应用限界上下文思想,但我们面临着一种明显的性能问题。例如,我们有不同的类(在不同的上下文中)来表示系统中的用户:Person
在我们的核心域上下文和User
安全上下文中。因此,我们为每个聚合有两个不同的存储库,但它们使用 DB 中的同一个表,有时访问相同的数据。
在这种情况下,是否有最小化数据库往返的通用解决方案?是否有处理它的 ORM,或者我们应该自己编写一些缓存系统?
upd:数据库来自旧版应用程序,我们必须“按原样”使用它
因此,我们为每个聚合有两个不同的存储库,但它们使用 DB 中的同一个表,有时访问相同的数据。
您将两个聚合存储在同一个表中这一事实表明设计存在问题。在这种情况下,您似乎有两个有界上下文 - 核心域的 BC(Person is here)和身份/访问 BC(User is here)。BC 是相关的,后者可以看作是前者的上游。Person
核心域中的A在User
身份 BC 中有一个对应,但它们并不是完全一样的东西。
除了 BC 之间的这种关系之外,还有关于行为所有权的问题。例如,Person 和 User 都可能有一个名字,要确定的是谁拥有更改名字的行为。这可以通过多种方式实现。人可能有自己的名字,更改应该传播到身份 BC。类似地,用户可能拥有对名称的更改,在这种情况下,它们必须通过同步机制传播给 Person。
总的来说,您的问题可以通过两种方式解决。首先,您可以将 Person 和 User 聚合存储在不同的表中。任何给定的查询都应该只使用这些表之一,并且它们可以在最终一致的情况下进行同步。另一种方法是将行为域模型与为查询设计的模型(读取模型)分离。这样,您可以创建一个旨在为特定屏幕提供服务并具有自定义查询的读取模型,甚至可能在 ORM 之外。
如果所有用户也是个人(有时外部服务也被建模为特殊用户),用户和个人应该在数据库上共享的唯一数据是他们的标识符。实际上,域模型中的每个实体都应该只保存对它们确保其不变量所需的数据的引用。
此外,我猜用户是由用户名标识的,而人员是由其他东西标识的(增值税代码左右..)。
因此,最简单的优化技术是避免将那些不需要确保其不变量的信息封装在实体中。
此外,您只需要一种有效的上下文映射技术即可在需要时轻松地从 User 传递到 Person。我为此使用共享标识符。
例如,您可以在 User 类中公开 Person 的标识符,以便对 Person 的存储库的简单查询可以为您提供所需的数据。
最后,我建议您阅读有关聚合根设计的 Vaughn Vernon 系列。