Doctrine OneToOne身份通过外部实体异常刷新

时间:2015-05-22 17:02:01

标签: php symfony doctrine-orm doctrine

我有UserUserProfile与OneToOne相关的Doctrine ORM实体。它们应该始终成对存在,没有User没有UserProfile

用户应从自动增量获取其ID,而UserProfile应具有用户ID。所以它们都应该具有相同的ID,并且没有其他列来设置关系(Doctrine docs: Identity through foreign Entities)。

UserProfile的id同时是主键(PK)和外键(FK)。

我设法设置了它,但它要求首先保存用户,并且只在以后创建UserProfile并在单独的步骤中保存。

我想要的是UserProfile总是在构造函数中使用User创建,但是如果我这样做,我会得到以下异常:

Doctrine\ORM\ORMInvalidArgumentException: The given entity of type 'AppBundle\Entity\UserProfile' (AppBundle\Entity\UserProfile@0000000052e1b1eb00000000409c6f2c) has no identity/no id values set. It cannot be added to the identity map.

请参阅下面的代码 - 它有效,但不是我想要的方式。 php评论显示了我想要实现的目标。

Test.php

/**
 * It works, both saving and loading.
 * BUT, it requires that I create and save UserProfile 
 * in a separate step than saving User step.
 */

// create and save User
$user = new User();
$objectManager->persist($user);
$objectManager->flush();

// create and save UserProfile (this should be unnecessary)
$user->createProfile()
$objectManager->flush();

User.php

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="AppBundle\Entity\UserRepository")
 * @ORM\Table(name="users")
 */
class User
{
    /**
     * @var int
     *
     * @ORM\Column(name="uid", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * It's NULL at first, I create it later (after saving User).
     * 
     * @var UserProfile|null
     *
     * @ORM\OneToOne(targetEntity="UserProfile", mappedBy="user", cascade="persist")
     */
    private $profile = null;

    public function __construct()
    {
        // I want to create UserProfile inside User's constructor,
        // so that it is always present (never NULL):
        //$this->profile = new UserProfile($this);

        // but this would give me error:
        //
        // Doctrine\ORM\ORMInvalidArgumentException: 
        // The given entity of type 'AppBundle\Entity\UserProfile' 
        // (AppBundle\Entity\UserProfile@0000000058af220a0000000079dc875a)
        // has no identity/no id values set. It cannot be added to the identity map.
    }

    public function createProfile()
    {
        $this->profile = new UserProfile($this);
    }   
}

UserProfile.php

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="profiles")
 */
class UserProfile
{
    /**
     * – UserProfile's "uid" column points to User's "uid" column
     * – it is PK (primary key)
     * - it is FK (foreign key) as well
     * – "owning side"
     *
     * @var User
     *
     * @ORM\Id
     * @ORM\OneToOne(targetEntity="User", inversedBy="profile")
     * @ORM\JoinColumn(name="uid", referencedColumnName="uid", nullable=false)
    */
    private $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }    
}

测试应用:https://github.com/MacDada/DoctrineOneToOneTest

1 个答案:

答案 0 :(得分:1)

请记住,实体对象需要由E​​ntityManager保存。 仅仅将该类作为对另一个类的引用并不会使entityManager意识到两个类都存在的事实。

您应该将实际的userProfile持久保存到EntityManager,以便能够保存关系。

因负面评论而更新:

请阅读Doctrine文档......你应该坚持下去!

以下示例是本章User-Comment示例的扩展。假设在我们的应用程序中,每当他写第一条评论时都会创建用户。在这种情况下,我们将使用以下代码:

<?php
$user = new User();
$myFirstComment = new Comment();
$user->addComment($myFirstComment);

$em->persist($user);
$em->persist($myFirstComment);
$em->flush();

即使您持有包含新注释的新用户,如果您删除了对EntityManager#persist($ myFirstComment)的调用,此代码也会失败。 Doctrine 2不会将持久化操作级联到所有新的嵌套实体。

<强> UPDATE2: 我理解你想要完成的是什么,但是按照设计你不应该在你的实体中移动这个逻辑。实体应该代表尽可能少的逻辑,因为它们代表了你的模态。

说实话,我相信你可以完成你想做的事情:

$user = new User();
$profile = $user->getProfile();
$objectManager->persist($user);
$objectManager->persist($profile);
$objectManager->flush();

但是,您应该考虑创建一个包含entitymanager的userService,并使其负责创建,链接和持久化user + userProfile实体。