6

我一直在阅读很多关于 DDD 的文章,并注意到大多数人在持久化到数据库时都使用 GUID 作为他们的 ID。他们说 GUID 可以很好地扩展,并且在可扩展性方面,自动递增 ID 是一个很大的禁忌。

我现在很困惑是使用GUID还是auto-increment.

基本上域是关于membership system (binary tree). (tracking of register members)

第一个要求是我们应该有一些可以在系统中唯一标识它们的东西(我们称之为Account No.7digit)。

然后 newMembers可以被另一个注册Member。我们称之为推荐。

现在我打算做的是将MemberIdGUID 类型作为 DomainObject Id,它用作将用于连接的主键、外键(在 Referral 上,referer_id 将是 GUID MemberId)。AccountNo将是一个自动增量列,或者它可能会通过 MAX() + 1 从存储库中获取。主要用于系统和链接中的搜索功能。

DomainObject 的 ID 是否应该对系统用户隐藏,因为它只是一个技术实现?

两者结合好吗?GUID 作为数据库中的 row_id(代理键)。和(自然键)的自动增量?

从构造函数中排除 是否可以,AccountNo因为无论如何它都会自动递增?是否需要强制执行不变量?那么从存储库中获取下一个 ID 是要走的路并包含AccountNo在构造函数中吗?

我是否应该坚持使用 Auto-Increment ID 而忘记 GUID,删除MemberId并让其AccountNo成为 DomainObject 的 ID?

笔记:

我不会建立某种下一个 Facebook。

我只想练习 DDD 的战术方面,以了解如何在了解其优点和缺点的情况下做出艰难的架构决策。

我只是想练习 DDD 的战略方面,以了解如何在了解其优点和缺点及其实施的情况下做出艰难的架构决策。

如果我们将使用会员注册制作 3 个场景:

  • 第一种情况:会员注册每分钟发生一次。
  • 第二种情况:会员注册每小时发生一次。
  • 第三种情况:会员注册每天最多发生 5 次。

它将如何影响决策?

技术栈:

  • ASP MVC 5
  • 数据库服务器 2014
  • C#
  • 简洁的 ORM
4

4 回答 4

4

你的问题可能有太多的问题无法给你一个完整的答案,因为ID设计并不简单,而且有很多方面。我可以推荐 Vaughn Vernon 的《实施 DDD》一书,它有一个专门介绍身份设计的部分(第 5 章“实体”-唯一身份)。

无论如何,我都会尝试为您指出正确的方向,而不会背诵该章中的所有内容:-)。

你需要什么?

您已经提出了一些关于 ID 设计的问题,但您还需要提出更多问题。只有这样,您才能决定 GUID、DB 生成的 ID 还是不同的 ID 是否合适。

  • ID 的域意义是什么?可能 ID 只是为了促进技术解决方案而存在,但根本不是域的一部分?
  • 谁提供身份证?这可能是用户、应用程序、数据库甚至是另一个限界上下文。
  • 什么时候需要身份证?在创建关联实体之前,在创建时,还是仅在实体被持久化时?

这些问题的答案将限制您可以使用的 ID 生成类型。

你应该知道什么

关于 ID 设计有一些规则。强烈建议您遵循它们,以免您以后误伤自己:

  • 确保您的 ID 是唯一的。对于用户提供的 ID,这可能尤其令人担忧。您需要强制执行唯一性并让您的用户能够检测现有 ID。对于应用程序生成的随机 ID 或 DB 生成的 ID,这通常不是问题。
  • 确保您的 ID 稳定。永远不要更改实体的 ID!毕竟,ID 是用来引用实体的。这样做的结果是,您不应将可能更改的内容作为 ID 的一部分。例如,一个人的姓氏可能不是一个好的选择,因为当某人结婚时这可能会改变(并且由于非唯一性也可能是有问题的)。
  • 如果 ID 只是一个技术概念,请隐藏它们。从 DDD 的角度来看,将技术概念作为域模型的一部分是错误的。

例子

以下是如何找到 ID 设计的示例:

允许稍后创建 ID(即通过持久性)意味着您在创建实体时确实有一个没有 ID 的实体。因此,如果您需要早期或即时 ID,则不能使用 DB 生成的 ID(除非您接受联系 DB 只是为了获取 ID)。

然后您可能会认为用户对 ID 不感兴趣,因此必须指定 ID 会很奇怪。这留下了应用程序生成的 ID。

对于应用程序生成的 ID,您需要确保 ID 是唯一的。这对于单实例应用程序来说是微不足道的,但一旦您创建具有多个应用程序实例的负载平衡设置,问题就可能更大。这就是为什么很多人一开始就使用随机 ID(例如 GUID)的原因,所以他们在横向扩展时不会遇到死胡同。

如你所见,这个例子做了很多假设。没有对错之分,但有了上述问题,您应该能够做出明智的决定。

于 2015-07-28T12:09:49.583 回答
4

我只想练习 DDD 的战术方面,以了解如何在了解其优点和缺点的情况下做出艰难的架构决策。

你错了。你不能通过战术来学习战略。战术是 实施战略的方法。但是你首先需要一个策略。

无论如何,关于您的问题,这很简单:使用 Guid。它有2个优点

  1. 全局标识符
  2. 可以从应用程序轻松生成。自动递增的 id 意味着复杂的服务或对数据库的依赖。不要让你的生活复杂化。

自然 id,如 AccountNo,也应该使用。但是,该指南是出于技术目的而存在的。自然键格式将来可能会改变,Guid 可以轻松支持自然键多种格式。

作为一种实践,最好将您的实体 id 作为值对象(即使它只是 Guid)。您也可以合并 guid AccountNo,VO 不需要只有一个值。例如,在我当前的应用程序中,我有一个ProjectId(Guid organization,Guid idValue)and ProjectAssetId(Guid organization,Guid projectId,Guid idValue)

于 2015-07-28T15:06:38.703 回答
2

请允许我捍卫自动增量的想法。的确,GUID 更具可扩展性。但是任何设计师在某些时候都应该问的一个重要问题是“我需要多少可扩展性?”

答案很少是“尽可能多!” 在现实世界中,一切都是有界限的。我们的数据库模拟现实世界。

例如,如果您与人(用户、客户、学生等)一起工作,一个 64 位整数可以多次包含地球上的整个人口。很多次。我们在这里谈论的是“银河帝国的人口”。使用bigint,您几乎可以唯一地识别宇宙中的每个原子。

不要偷懒,尤其是在设计阶段。设计一个合理的安全边际,然后继续。任何不必要的增加系统的复杂性和“摩擦”。

我在这个领域的经验现在以几十年来衡量——其中有几个。在那段时间里,我从来不需要使用 GUID 来实现可伸缩性。我发现 GUID 的唯一实际用途是在不同的(通常是远程的)数据库中创建实体,然后必须将这些数据库合并到一个中央数据库中。GUID 消除(从统计上讲,即)在合并期间发生冲突的可能性。

于 2015-07-30T19:25:04.867 回答
0

他们说 GUID 可以很好地扩展,并且在可扩展性方面,自动递增 ID 是一个很大的禁忌。

自增整数的主要可伸缩性问题在于插入:由于新值在值范围的上限“聚集”在一起,它们往往会碰到 B-Tree 的同一“边”(并且可能相同)叶节点),导致锁存并降低并发性。

每分钟插入一次,您根本看不到任何这些,因此请根据其他标准选择您的密钥。正如您所描述的,自动增量整数在您的场景中可以很好地发挥作用......它们更轻量级并且可能比 GUID 执行得更好。如果 32 位变体不够宽,请使用 64 位。


顺便说一句,自动递增整数不是通过查询生成的MAX() + 1——所有 DBMS 都有自己的高性能“序列生成器”版本,您可以直接使用。

您还可以将生成的值直接返回给客户端,而无需额外的往返(例如 Oracle 的 RETURNING 或 SQL Server 的 OUTPUT 子句)。不幸的是,ORM 并不总是能很好地解决这个问题......

于 2015-07-28T18:24:24.623 回答