Doctrine2中关系实体(也是关系的实体)上的复合主键或代理主键

时间:2013-05-17 09:56:16

标签: doctrine-orm foreign-keys relationship composite-primary-key surrogate-key

我有一个大型数据库,我有实体关系。这完全是因为Doctrine 2手册中的the following comment:我需要在我们的关系中存储其他属性,因此关系成为一个实体。

通常我们使用生成的id作为实体,使用复合键来表示关系。在这种情况下,实体是一种关系,因此使选择更复杂......

请注意这里我不是在谈论自然键。我正在使用一个复合键,它由id组成,它们是在各自拥有的实体中使用自动增量策略创建的整数。

我发现在关系实体上使用复合主键存在一些缺点

  • 我需要在创建实体及其关系之间保持调用(在我可以将其用作复合主键中的外键之前,在实体上生成键)。
  • 要将其他实体与关系实体相关联,我们需要在这些实体中再次为复合键中使用的ID添加列。如果我使用代理主键,我只需要一个包含一个id的列。

我还看到了使用复合键的一些优点,例如:

  • 他们不再需要某些连接查询,而是可以构建查询以使用复合键直接提取信息。

但现在使用复合键的最重要的论点如下:

  • 当User和SomeEntity之间的关系被删除并稍后再次创建时(我们的应用程序模型中可能会发生这种情况),我们还需要恢复对所有其他相关实体的访问。 如果在代理主键上使用自动增量策略创建User和SomeEntity之间的关系。恢复的(新)关系将获得新的主键(id)。因此,不再可访问相关实体(使用“旧”键存储)。 如果我在关系上使用复合键,我可以简单地恢复关系(它获得相同的复合键值),并且我可以立即再次访问其他相关实体。

有没有人有类似情景的经验?是否有其他解决方案可以使其正常工作。我错过了任何重要的缺点或优点(当使用Doctrine ORM时)。

我能想到的另一个选择是向User SomeEntity关系添加一个状态。我们可以将状态更改为禁用状态,而不是删除条目。通过这种方式,我们可以使用代理键而不是复合键,因为该条目永远不会被删除...

非常感谢反馈......

对于感兴趣的人来说,还有关于Stack Overflow上的代理与复合键的讨论:(click)

1 个答案:

答案 0 :(得分:1)

我建议让你的两个外键成为复合主键。

您的关联实体将通过其两个关系的ID来识别。

理论上,Doctrine的UnitOfWork / CommitOrderCalculator应该以正确的顺序插入元素,因此,您不必处理持久性命令。

你的映射在最后看起来像这样(注释示例):

<?php

class UserGroup
{
    /**
      * @ORM\ManyToOne(targetEntity="User")
      * @ORM\Id
     **/
    public $user;

    /**
      * @ORM\ManyToOne(targetEntity="Group")
      * @ORM\Id
     **/
    public $group;
}