【问题标题】:(DDD) Retrieve entity stored in multiple databases(DDD) 检索存储在多个数据库中的实体
【发布时间】:2021-10-23 03:07:52
【问题描述】:

我正在着手开发一个新的(dotNet Core)WebAPI,其中一些数据将从应用程序的数据库中读取(使用 EFCore),一些数据来自 Microsoft Graph。特别是,一个人的电子邮件地址和全名可以从 Graph 中检索到,并且特定于应用程序,我们想知道该人何时在应用程序中注册,以及该人上次登录的时间。在领域驱动设计方面,我想说所有这些属性都属于一个实体User。但是,我正在努力解决如何填充这样的用户实体。是否有关于如何填充其信息存储在两个不同数据库/服务中的对象的任何指导?请注意,Graph 中的信息无需更新。

我正在考虑 3 个选项:

  1. 最简单的选择是将实体直接存储在数据库中。使用UserRepository,我可以首先从数据库中获取记录,然后使用从 Graph 中检索到的数据对其进行补充。

  2. 更复杂的选项是拥有与数据库结构相对应的类,并让UserRepository 从各种数据库/服务中获取数据,然后将其映射到真实实体。此选项的好处是实体与数据库完全断开连接,但在将实体来回映射到数据库记录方面需要做很多工作。

  3. 我想到的最后一个选项是将应用相关的用户信息(存储在数据库中)和身份相关的信息(在 Graph 中)视为两个不同的对象。组合这两条数据的负担将落在我的 API 的使用者身上。

如果预算有限且期限紧迫,您会怎么做?

【问题讨论】:

  • 您的数据分布在多个数据库中的事实是一个重要提示[tm],您不是在建模单个域实体,而是可以通过以下方式连接(用于报告目的)的多个实体一个通用的相关标识符。
  • 数据的波动性如何?例如,它的波动性是否足以成为该方法的一个因素?

标签: architecture repository domain-driven-design


【解决方案1】:

我不得不承认我并不是一个真正有意识的 DDD 追随者。

您可以有一个UserAppUsageHistory 实体或类似实体,将数据放入其中(您的选项 3)。您只需要一种明智的方式让 API 使用者加入他们 (UserId?)。假设 UserAppUsageHistory 数据比 User 数据更新更频繁,这可能效果很好。

顺便说一句,从 API 消费者的角度来看,您确实想询问消费者他们想要什么(例如协同设计),因为这是获得对其消费者有利的 API 的最佳方式。

(您的选项 2) ...但是在将实体映射回来和 转入数据库记录

从 API 消费者可用性的角度来看,这听起来有点令人担忧,如果这对你来说很难,对他们来说也不会更容易。

选项 1 和 3 存在延迟问题 - 确定您可以从本地副本中提供数据 - 但它是最新的吗?也许这没关系?使用选项 1,您只能获得更有限的数据量(这是否符合目的?)。

1 和 3 之间的主要区别是历史数据结构发生变化的可能性有多大?因为每当它发生变化时,它都可能会影响User 所触及的一切。

这归结为您希望遇到的一组问题以及哪些好处之间的权衡。

选项 3 的另一个优点是,由于它们是松散耦合的,因此您始终可以将这些数据的收集工作外包给某个后台进程,以在您认为合理的范围内保持已知用户数据的更新。不过,对于新添加的用户,您可能需要一些特殊/额外的东西。

如果预算有限且期限紧迫,您会怎么做?

这取决于。制造技术债务很糟糕,但有时这是不可避免的。如果您能应付额外的工作,从长远来看,选项 3 听起来更安全、更灵活。

重要的考虑因素是:

  • 数据结构/模式的性质(多少,有多复杂)?更复杂的 -> 使用单独的实体。
  • 该结构/模式发生变化的可能性?如果可能的话 -> 远离User
  • 数据的波动性如何(记录更新频率)?
  • 您拥有的数据是最新的有多重要?

关于最后两个:设计一个策略来处理获取数据,看看这是否会影响你对问题的决定。如果不稳定,选项 3 对我来说听起来更好。

最后,您是否考虑过 LazyLoad(模式)?它不能直接解决您的问题,但是如果您可以单独获取历史数据,那么它会使初始 User 实例化更简单快捷,因为您只需在运行时加载核心 User 数据,并且只加载历史数据如果/当它被明确要求时。

【讨论】:

    【解决方案2】:

    作为一般准则,我建议的是,持久性技术(或组合)是隐藏在存储库后面的实现细节。

    根据 DDD,UserRepository 应返回域对象,在本例中为 User 聚合。这排除了选项 3

    关于选项 1 和 2,如果我理解正确,您正在考虑存储库是否应该直接在数据库中实现映射或存储实体。

    我会说理想情况下您希望拥有映射。这样,您就可以在域对象和持久性结构之间完全隔离。这应该为您的代码库提供更大的灵活性。

    但是,如果您的预算有限且时间紧迫,那么不使用映射应该没问题。但是,您应该尝试确保将来可以在存储库中添加映射,而不会影响存储库 API(=不影响使用存储库的任何代码)。

    【讨论】:

      猜你喜欢
      • 2018-08-03
      • 2013-12-05
      • 2012-03-10
      • 1970-01-01
      • 2010-11-24
      • 2011-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多