如何通过学说实体之间的 ID 建立一对一的关系

Posted

技术标签:

【中文标题】如何通过学说实体之间的 ID 建立一对一的关系【英文标题】:How to establish one-to-one relation through IDs between doctrine entities 【发布时间】:2016-10-04 17:11:28 【问题描述】:

我希望这是一个直截了当的过程,但似乎 Doctrine 并不真正喜欢通过 ID 链接实体的想法。

我打算做的只是通过将一些字段从表传送到新表来规范化表,而不是在原始表中添加新的引用字段来保存新对应记录的 ID,确保新的子表中的记录将具有与其父行相同的 ID。

这是我所拥有的一个例子:

一个 User 实体,带有注释字段 $user 以将 UserDetail 实体中的列 ID 引用到自身的 ID

/**
 * @ORM\Table(name="user", options="collate"="utf8_general_ci", "charset"="utf8", "engine"="InnoDB")
 * @ORM\Entity
 */
class User extends Entity

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id

     /**
      * @ORM\OneToOne(targetEntity="UserDetail", cascade="persist")
      * @ORM\JoinColumn(name="id", referencedColumnName="id", nullable=true)
      */
     private $userDetail;

     ...

这是 UserDetail,其 ID 的 @GeneratedValue 已删除

/**
 * @ORM\Table(name="user_detail", options="collate"="utf8_general_ci", "charset"="utf8", "engine"="InnoDB")
 * @ORM\Entity
 */
class UserDetail extends Entity

    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\Id
     */
    private $id;

    ...

在这一点上,我的期望是能够做这样的事情:

$user = new User();
$userDetail = new UserDetail();

$user->setUserDetail($userDetail)

$entityManager->persist($user);
$entityManager->flush();

将两条记录持久化到 useruser_detail 表中,ID 相同,但实际情况是,没有为UserDetail 的标识符,学说会抱怨缺少的 ID,Entity of type UserDetail is missing an assigned ID for field 'id'.

当然,也可以通过多次调用手动完成这项工作

$user = new User();
$entityManager->persist($user);
$entityManager->flush();

$userDetail = new UserDetail();
$userDetail->setId($user->getId)    
$user->setUserDetail($userDetail)

$entityManager->persist($user);
$entityManager->flush();

但我仍然希望有一个正确的配置(注释)可以帮助我避免这些额外的步骤,并将通过实体 ID 处理一对一的关系留给 Doctrine。

【问题讨论】:

生命太短暂,不必担心这些事情。将 UserDetail::id 定义为您的基本 autoinc 主键,然后添加一个 user_id 列以用作对用户的引用。而且我知道。您想让它们保持同步并且没有额外的数据库列,但这真的很重要吗?使用 Doctrine 时,认为对象而不是数据库,生活会很美好。 @Cerad 大声笑,不能再同意了,但不幸的是,在这个应用程序中,我们的团队(公司)不负责数据库,并且由于还有其他消费者,所以包括附加列是不可能的(基于 Java)可以更轻松地处理此类场景 我已经看到这个问题被问了几次,但从未见过开箱即用的解决方案。应该能够实现您自己的自定义 id 生成器。尚未找到任何关于此的最新教程,但您可以从这里开始:groups.google.com/forum/#!topic/doctrine-user/GxXAO3-g4vo 谢谢@Cerad,这里也一样,会看链接,如果能想出答案就留下答案 【参考方案1】:

这未经测试,但根据文档 (http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/tutorials/composite-primary-keys.html),我认为以下方法可能有效:

    /**
     * @ORM\Table(name="user_detail", options="collate"="utf8_general_ci", "charset"="utf8", "engine"="InnoDB")
     * @ORM\Entity
     */
    class UserDetail extends Entity
    
        /**
         * @var integer
         *
         * @ORM\OneToOne(targetEntity="User")
         * @ORM\JoinColumn(name="id", referencedColumnName="id")
         * @ORM\Id
         */
        private $user;

    ...
    

【讨论】:

谢谢,我会试一试,让你知道它是否有效 很遗憾这不起作用,它实际上导致了一个无限循环,function nesting level of '1000' reached, aborting!||"file":"Doctrine/Common/Persistence/Mapping/AbstractClassMetadataFactory.php","line":187 对不起,阿里,我已经调整了答案中的代码 - 我的意思是它是与用户实体的正确关联,但忘记更改属性名称。 不用担心,变量名显然不会影响结果

以上是关于如何通过学说实体之间的 ID 建立一对一的关系的主要内容,如果未能解决你的问题,请参考以下文章

学说中的关系

如何在没有连接列的情况下映射一对一关系(实体通过它们的 ID 连接)?

实体框架代码优先关系 - 如何定义两个对象之间的关系:两个实体之间的可选一对一

数据立方建立-如何实现一对多,多对多

核心数据关系

在Yii2中创建一对多关系