对象应该知道自己的ID吗?


22

obj.id似乎相当普遍,似乎也落入了对象可能了解的自身范围之内。我发现自己在问为什么我的对象应该知道自己的ID?

它似乎没有理由拥有它吗?存在它的主要原因之一是检索它,因此我的存储库需要知道它,然后将其用于数据库交互。

我还曾经遇到一个问题,我想将对象序列化为RESTful API的JSON,其中id似乎不适合有效负载,但是仅URI并将其包含在对象中使事情变得更加困难。

对象应该知道它自己的ID吗?为什么或者为什么不?

更新条款

  1. id:对象的标识符属性。用数据库术语来说,代理键不是自然键。
  2. 对象:系统中的实体或其他可唯一标识的对象。

1
为了保持抽象,如果没有理由存储信息,请不要存储。它只会造成头痛。

3
如果您不知道对象的唯一键,您将如何更新数据库中的数据或让用户从列表中选择一个事件?
NoChance 2012年

@EmmadKareem我要说的是集合(存储库)知道id,那么为什么对象本身需要这样做。如果我正在渲染列表,则可能会渲染集合,该集合知道ID的信息。
xenoterracide 2012年

如果您不使用与对象一起存储的id thats,并且从未打算或不想使用它,则显然不需要它。
GrandmasterB 2012年

@GrandmasterB当然可以使用id了,问题是您是否将id与对象一起存储在内存中,为什么?
xenoterracide 2012年

Answers:


8

简短的回答:如果要引用对象,则必须在对象中包含对象标识符

对于计划使用对象集合并计划引用单个对象/实体的方案,则应包括标识符。但是,在某些情况下,像这样的自然键/标识符DateTime可以人为地满足该需求。

另外,您可能会将DTO作为对象的轻量级容器,它本身可能会跳过/包含对象标识符。实际上,所有这些选择实际上取决于您的业务用例和需求

编辑:如果要标识您的对象,则需要具有标识符。该标识符可以是代理ID,日期时间,GUID等,基本上,任何可以以独特方式将您的对象与他人标识的对象。


2
为什么将它们包括在对象中,而不是仅包含在集合中(假设集合是某种字典)?
xenoterracide

我的意思是,如果要标识对象,则需要有一个标识符。它可以是Id,日期时间等...可以从其他对象识别您的对象的任何东西。
EL Yusubov 2012年

1
当然,我的问题更多是为什么对象本身需要知道该标识符。
xenoterracide 2012年

澄清一下,我的意思是一个代理id,通常是诸如datetime或vin数字之类的东西是自然的,因此是数据的一部分,并且没有命名id(或者至少我不会)
xenoterracide 2012年

6

为了使我的回答像您的问题一样抽象,我认为您实际上已经回答了自己的问题。

如果需要,对象应该知道其自己的ID。

如果不需要,一个对象就不应该知道它的ID(或者甚至有一个ID)。

正如您所指出的,在某些情况下,保留对象或知道其ID是否不便或不必要。但是在其他情况下,使对象知道其ID更方便。根据您的用途对对象进行编码。


在什么情况下知道ID是方便的?我一直在思考它,并认为它们中的大多数可能只是基于它的编码方式,也许是用于呈现obj.id而不是呈现集合本身的for循环。
xenoterracide 2012年

1
@xenoterracide-异步查看和更新​​数据库记录是一个示例。在某些情况下,除了ID之外,我没有足够的信息来唯一标识一条记录,因此将ID与记录对象保持在一起是有意义的。

但这是原因还是结果?这是一个要求吗?如果您的存储库/集合/数据映射器(或其某些链)负责持久化更新,并且它知道该ID并能够将其传递给我...我想了解一下是否有原因,或者是否之所以在这里,是因为很多人都在使用主动记录模式。
xenoterracide 2012年

@xenoterracide-在我正在考虑的情况下,这绝对是因果关系。在某些情况下,保持ID与对象关联起来要方便得多。您的问题很好,因为它挑战了许多人的基本假设。当我们深入研究这样的假设时,我们倾向于学习。另一方面,不要过度分析并朝相反的方向发展。否则,您最终将不得不做出与首先分解的神圣神圣的声明相同的时间。

4

包含ID是很常见的,但使用字典也很常见,即每个对象与其ID关联的数据结构,您可以通过知道相应ID的方式轻松检索此对象,但是对象不知道它。

例如,如果要使用两种方法创建API:

然后,您无需在第二个请求的JSON响应中重新发送ID 452。API的用户已经知道ID。


4

我认为这是主观的,取决于您的设计。

尽管大多数情况下,这似乎是来自活动记录的设计。在活动记录中,您的实体具有执行数据库操作的方法,因此还必须知道它的数据库标识符。

当使用其他模式(例如带有数据映射器的存储库)时,将这些数据存储在对象中变得不必要,并且可能不合适。

以一个Person物体为例。我的名字在一个家庭中可能是唯一的,也可能不是唯一的。随着人口的增长,更大的名字不再是唯一的,因此我们为越来越大的系统提出了替代标识符。这些示例包括:我的驾驶执照和社会保险号。我并非天生就分配了ID,因此必须申请所有这些ID。

由于它们不是通用的,因此大多数不能为软件提供良好的主键/ ID。SSN至少在其特定系统之外,显然对社会保障局来说是唯一且一致的。由于我们通常不是此信息的提供者,因此您不会称其为,id而是称其为代表的数据,例如SSN。有时甚至包含完全组合的对象,例如DriversLicense,可能包含驾驶执照所包含的所有信息。

因此,所有常规ID都是系统中的代理键,并且可以用内存引用替换,仅包含ID以使查找和持久记录变得更加容易。

由于an id不是概念数据,因此我怀疑它(通常)是否属于对象内,因为它不是来自域。而是应保留其目的,即识别没有其他方法可以表示唯一标识的对象。这可以在存储库/集合中轻松完成。

在软件中,如果您需要将对象表示为列表或将其持久化,则只需从存储库/集合对象或与此相关的其他对象中进行操作即可。传递到数据映射器(如果是单独的)时,只需传递即可.update( id, obj )

免责声明:我尚未尝试构建一个不包含实体内ID的系统,因此可能证明自己是错误的。


2

正如GlenH7在评论中指出的那样,这是一个好问题,因为它挑战了许多人理所当然的东西。但是,我的看法是,即使从概念上讲遗漏了id,但务实的做法是将id与对象的ID保留在尽可能多的系统层中。它的价格不高,但是在事情开始崩溃时可以派上用场。

实体可能不需要知道其ID,就像一个人不需要知道其个人识别码,驾驶执照号码或您所在位置可能正在使用的任何其他标识符一样。您当然可以在大多数时间没有它。但是,以防万一,明智的做法是对您进行某种身份识别。

物体也可以这样说。无论数据访问层的复杂程度如何,该对象最终都会映射到某个数据库条目。该条目可能只能通过对象的ID进行唯一标识。如果是这样,那么无论我是在调试某些UI代码,业务层中的数字处理,存储库本身还是跨Web服务的依存系统,我都希望随时提供此信息。或者我是否正在浏览错误日志。

在您的情况下,如果您只是从数据库中获取数据并通过Web服务推送数据,那么将ID留在外面可能是正确的选择。我只是不认为这比将其保留在一般情况下更有意义。


2

没错,只要您仅需要在存储库上下文中知道它,就不需要将id存储在对象中。

当您将对象传递给该上下文之外的代码时,情况发生了变化,该代码没有按id请求对象(因此尚不知道),但是出于任何目的都需要id(例如,将其放在列表中)稍后将通过另一个代码从存储库中请求的ID的数量)。

在这种情况下,您有两种选择:

  • 在存储库上下文和需要id的函数之间的整个函数链中引入新的函数参数'id'

  • 在对象中包含ID

在大多数情况下,将id存储在对象中将是更好的解决方案。当在不可预见的地方需要id时,它还将减少代码更改,并且有时可能有助于调试。

这就是为什么我这样做的原因。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.