Domain driven design DDD-验证实体在其他有界上下文中的存在性

Domain driven design DDD-验证实体在其他有界上下文中的存在性,domain-driven-design,cqrs,Domain Driven Design,Cqrs,我有一个问题,关于在有界上下文中验证实体存在的最佳实践是什么。这在DDD中是有效的方法吗?基本上,BC应该是自包含的部署,也就是说,您不应该依赖可能不可用的另一个BC 我有2个BC在我的项目-成分和食谱。该公司销售散装配料,但也销售使用上述配料的预配置配方。现在这些是独立的BC,每个BC都有自己的成分实体 Recipe是具有成分列表的子实体的聚合根。在将配料添加到配方BC的配料列表之前,验证配料BC中是否存在配料是否合理 配料只能通过配料BC进行修改,事件将在BC发布,配方BC将订阅并更新其自己

我有一个问题,关于在有界上下文中验证实体存在的最佳实践是什么。这在DDD中是有效的方法吗?基本上,BC应该是自包含的部署,也就是说,您不应该依赖可能不可用的另一个BC

我有2个BC在我的项目-成分和食谱。该公司销售散装配料,但也销售使用上述配料的预配置配方。现在这些是独立的BC,每个BC都有自己的成分实体

Recipe是具有成分列表的子实体的聚合根。在将配料添加到配方BC的配料列表之前,验证配料BC中是否存在配料是否合理

配料只能通过配料BC进行修改,事件将在BC发布,配方BC将订阅并更新其自己的配料,以应对任何更改,即价格/名称。为了使其有效,成分必须是有效的。那么如何保持这些BC之间的一致性呢?我是否将域服务注入配方BC并在添加它们之前验证成分的存在?我也在使用CQR,因此我可以直接将服务注入处理程序,而不是创建配方的工厂,或者这是使用域服务的正确方法吗


如果这是一个值得关注的问题,那么就有点迷失了。一般来说,你的食谱应该只关注成分的唯一标识符,而不是它的细节。配方一致不需要成分的详细信息

我会假设某些操作,例如用户与UI交互时,会将配料添加到配方中。我还假设可以添加的成分来自只返回有效成分的查询。除非你有理由担心某事/某人会破坏这一过程,否则你很可能会花时间解决一个不太可能成为真正问题的问题

如果这实际上是一个真正的问题,那么是的,您可以在添加成分之前验证成分是否存在。然而,这可能最好在配方BC的边界附近,在命令验证器中完成

有界上下文是概念性的,通常不由单个类表示。我提到这一点是因为你问

我是否将域服务注入配方BC

你并不是真的注射到一个BC中。同样,如果您确实需要此验证,您可能会有一个验证类,该类通过API或数据库查询成分BC以确保其存在

配方BC将订阅并更新其自己的配料,以应对任何更改,即价格/名称

这是不必要的。配方中有对每种成分的引用,因此当您查询配方时,您可以同时查询成分列表和这些成分的详细信息。根据您的设置,这可能是SQL连接或其他方式。根据您的设置,可以采用多种不同的方式来完成。通常应避免在收据BC中缓存成分详细信息,除非您特别关注性能。缓存总是增加复杂性


在继续进行CQRS时,您会发现,许多您通常认为是命令问题的问题实际上在查询端更容易解决。

一般来说,您的配方应该只关注配料的唯一标识符,而不关注其细节。配方一致不需要成分的详细信息

我会假设某些操作,例如用户与UI交互时,会将配料添加到配方中。我还假设可以添加的成分来自只返回有效成分的查询。除非你有理由担心某事/某人会破坏这一过程,否则你很可能会花时间解决一个不太可能成为真正问题的问题

如果这实际上是一个真正的问题,那么是的,您可以在添加成分之前验证成分是否存在。然而,这可能最好在配方BC的边界附近,在命令验证器中完成

有界上下文是概念性的,通常不由单个类表示。我提到这一点是因为你问

我是否将域服务注入配方BC

你并不是真的注射到一个BC中。同样,如果您确实需要此验证,您可能会有一个验证类,该类通过API或数据库查询成分BC以确保其存在

配方BC将订阅并更新其自己的配料,以应对任何更改,即价格/名称

这是不必要的。配方中有对每种成分的引用,因此当您查询配方时,您可以同时查询成分列表和这些成分的详细信息 要素。根据您的设置,这可能是SQL连接或其他方式。根据您的设置,可以采用多种不同的方式来完成。通常应避免在收据BC中缓存成分详细信息,除非您特别关注性能。缓存总是增加复杂性


在继续进行CQRS时,您会发现,许多您通常认为是命令问题的问题实际上在查询端更容易解决。

感觉您的BCs边界是错误的。尝试找到他们为您的业务执行的业务功能。不要将实体的1对1名称映射为有界上下文的名称。在聚合之间,您无法保证一致性。即使你检查你的成分,它可能在那里,但1毫秒后它就消失了,你会继续执行你的逻辑,认为它在那里。我不明白为什么配料应该和配方分开。它有什么价值。

感觉你的BCs边界是错误的。尝试找到他们为您的业务执行的业务功能。不要将实体的1对1名称映射为有界上下文的名称。在聚合之间,您无法保证一致性。即使你检查你的成分,它可能在那里,但1毫秒后它就消失了,你会继续执行你的逻辑,认为它在那里。我不明白为什么配料应该和配方分开。它有什么价值。

在我的例子中,配料在它自己的BC中,因为这是主要领域。食谱是另一个拥有自己版本的配料的BC。我当然可以只引用配方BC中成分的ID列表,并通过查询在UI中获取ingr,但我假设BC应该自己工作,即即使成分BC不可用,配方仍然有效。如果我有一个有效的成分ID列表,但我无法获取任何成分ID,您如何解决这种情况?在DDD中,如果整个上下文都是自包含的,那么这是一个不值得关注的问题吗?关于配方,我确实需要关注配料,因为配方的成本是所有配料成本+管理费用的总和,没有配料,配方就不可能存在,因为它毫无意义。因此,我必须确保现有的有效成分正在通过。这就是为什么我在配方BC中有一个成分实体,因为它用于验证配方+成分的集合是否正确,并将其保留在自己的配方BC中。有没有更好的办法?我一般认为DDD不存在重复数据的问题,因为它试图解决域问题,而不是存储问题。回复您的第二条评论。请看我回答中的最后一句话。计算配方的总成本是一个阅读方面的问题!如果您说如果成本高于$XX,则无法创建配方,那么您可能需要在创建配方时在命令中传递配料成本。回复您的第一条注释BCs可以是自包含的,但仍然相互依赖以使整个系统工作。如果不是这样的话,您需要在每一个BC中缓存每个BC中的每一位数据,以确保始终能够检索到所需的数据。谢谢!这是有道理的,因为我的做法是错误的。我将根据这些知识修改我的方法。一般来说,你在什么时候询问另一个BC?如果我使用的是CQR,那么在查询处理程序中是否会在应用程序级别查询所有成分(即配方中存在的ID)?这可能也适用于您关于实体验证的观点,即在应用程序级别的命令中进行验证?。您在边界处提到过,这似乎是放置该逻辑的合适位置,使用一个域服务来查询另一个BC API。在我的例子中,配料在它自己的BC中,因为这是主域。食谱是另一个拥有自己版本的配料的BC。我当然可以只引用配方BC中成分的ID列表,并通过查询在UI中获取ingr,但我假设BC应该自己工作,即即使成分BC不可用,配方仍然有效。如果我有一个有效的成分ID列表,但我无法获取任何成分ID,您如何解决这种情况?在DDD中,如果整个上下文都是自包含的,那么这是一个不值得关注的问题吗?关于配方,我确实需要关注配料,因为配方的成本是所有配料成本+管理费用的总和,没有配料,配方就不可能存在,因为它毫无意义。因此,我必须确保现有的有效成分正在通过。这就是为什么我在配方BC中有一个成分实体,因为它用于验证配方+成分的集合是否正确,并将其保留在自己的配方BC中。有没有更好的办法?我通常认为DDD的数据复制不是一个问题,因为它试图避免重复
olve域而非存储。正在回复您的第二条评论。请看我回答中的最后一句话。计算配方的总成本是一个阅读方面的问题!如果您说如果成本高于$XX,则无法创建配方,那么您可能需要在创建配方时在命令中传递配料成本。回复您的第一条注释BCs可以是自包含的,但仍然相互依赖以使整个系统工作。如果不是这样的话,您需要在每一个BC中缓存每个BC中的每一位数据,以确保始终能够检索到所需的数据。谢谢!这是有道理的,因为我的做法是错误的。我将根据这些知识修改我的方法。一般来说,你在什么时候询问另一个BC?如果我使用的是CQR,那么在查询处理程序中是否会在应用程序级别查询所有成分(即配方中存在的ID)?这可能也适用于您关于实体验证的观点,即在应用程序级别的命令中进行验证?。您在边界处提到过,这似乎是通过使用域服务查询其他BC API来放置该逻辑的合适位置。因为成分可以自己存在,因为它们是要销售的主要域散装成分。如果某个成分被删除,我将引发一个域事件,该事件将根据其业务逻辑更新配方BC。我正在简化我的域模型,因为成分不仅仅是一个实体,而且对于整个域来说,它是聚合根。没有这样的有界上下文成分。试着找到你生意中有价值的部分。它可以是订购、交货、付款。这三件事是你生意兴隆所必需的。因为用户应该能够组装他的订单,支付费用,并获得它。配方和成分实体可能存在于所有这些实体中。在订单中,您的配料是orderItem,在付款BC中,您的配料是paymentProcess的一部分,在交付中,您的配料是装运总量的一部分。想象一下一条规则说你不应该选择DHL作为奶酪,因为他们不允许发货。所以在UI上,当您添加新配料时,应将其分布在所有需要该数据的微服务范围内的上下文中,以充分发挥其业务能力。因为配料可以独立存在,因为它们是要销售的主域散装配料。如果某个成分被删除,我将引发一个域事件,该事件将根据其业务逻辑更新配方BC。我正在简化我的域模型,因为成分不仅仅是一个实体,而且对于整个域来说,它是聚合根。没有这样的有界上下文成分。试着找到你生意中有价值的部分。它可以是订购、交货、付款。这三件事是你生意兴隆所必需的。因为用户应该能够组装他的订单,支付费用,并获得它。配方和成分实体可能存在于所有这些实体中。在订单中,您的配料是orderItem,在付款BC中,您的配料是paymentProcess的一部分,在交付中,您的配料是装运总量的一部分。想象一下,有一条规则说,你不应该选择DHL作为奶酪,因为他们不允许运送奶酪。因此,在UI上,当你添加新配料时,它应该分布在所有微服务范围内的上下文中,这些上下文需要这些数据,以充分发挥他们的业务能力。