使用自然键作为DomainObject或GUID +自动增量域驱动设计的ID

时间:2015-07-28 09:45:05

标签: database-design orm domain-driven-design primary-key-design

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

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

基本上,域名约为membership system (binary tree). (tracking of register members)

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

然后,另一个Members可以注册新的Member。我们称之为推荐。

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

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

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

可以从构造函数中排除AccountNo,因为它会自动递增吗?那么强制执行不变量的必要性呢?那么从存储库中获取下一个ID是否可以在构造函数中包含AccountNo

我应该坚持使用自动增量ID并忘记GUID,删除AccountNo并让MemberId成为DomainObject的ID吗?

注:

我没有建立下一个某种类型的脸书。

我只想练习DDD的战术方面,了解如何在知道PROS和CONS的情况下做出艰难的架构决策。

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

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

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

它将如何影响决策?

技术堆栈:

  • ASP MVC 5
  • Sql Server 2014
  • C#
  • Dapper ORM

4 个答案:

答案 0 :(得分:3)

在你的问题中可能有太多问题要给你一个完整的答案,因为ID设计不简单并且有很多方面。我可以推荐Vaughn Vernon的“实施DDD”一书,它有一个专门用于身份设计的章节(第5章“实体” - 唯一身份)。

无论如何,我试着指出你正确的方向,而没有背诵那一章中的所有内容:-)。

你需要什么?

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

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

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

你应该注意什么

关于ID设计有一些规则。强烈建议他们跟随他们,这样你以后就不会用脚射击自己:

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

实施例

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

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

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

使用应用程序生成的ID,您需要确保ID是唯一的。这对于单实例应用程序来说是微不足道的,但只要您创建具有多个应用程序实例的负载平衡设置,就可能会出现更多问题。这就是为什么许多人首先使用随机ID(例如GUID)的原因,因此当缩小时它们不会达到死胡同。

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

答案 1 :(得分:3)

  

我只想练习DDD的战术方面,以了解如何在知道PROS和CONS的情况下做出艰难的架构决策。

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

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

  1. 全局标识符
  2. 可以从应用程序轻松生成。自动递增的id表示复杂的服务或对db的依赖。不要让你的生活复杂化。
  3. 自然ID也应该像AccountNo一样使用。但是,Guid是出于技术目的。自然键格式将来可能会发生变化,Guid可以轻松支持自然键多种格式。

    作为一种做法,最好将您的实体ID作为价值对象(即使它只是Guid)。您也可以在AccountNo中加入guid,VO不需要只有一个值。例如,在我当前的应用中,我有ProjectId(Guid organization,Guid idValue)ProjectAssetId(Guid organization,Guid projectId,Guid idValue)

答案 2 :(得分:2)

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

答案很少#34;尽可能多!"在现实世界中,一切都有局限。我们的数据库模拟现实世界。

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

不要变懒,特别是在设计阶段。设计合理的安全边际并继续。任何更不必要的事情都会增加复杂性和摩擦力。系统。

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

答案 3 :(得分:0)

  

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

自动增量整数的主要可伸缩性问题是插入:由于新值在值范围的上限处“聚集”在一起,因此它们倾向于击中B树的相同“侧”(并且可能是相同的叶节点),导致锁存并降低并发性。

仅插入一分钟,您根本看不到任何此类内容,因此请根据其他条件选择您的密钥。就你所描述的而言,自动增量整数在你的场景中可以正常运行......它们更轻量级,并且可能比GUID更好。如果32位变量不够宽,只需使用64位。

BTW,查询MAX() + 1不会生成自动增量整数 - 所有DBMS都有自己版本的高性能“序列生成器”,可以直接使用。

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