Doctrine - 防止通过外国实体使用身份进行双重冲洗

时间:2016-09-19 07:47:55

标签: doctrine-orm

我有两个实体 - TestUserTestAddress。 Address与User具有OneToOne关系,它的主键也是User的外键。

/**
 * @ORM\Entity
 */
class TestUser
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue
     */
    private $id;
}


/**
 * @ORM\Entity
 */
class TestAddress
{
    /**
     * @ORM\Id
     * @ORM\OneToOne(targetEntity="TestUser")
     */
    private $user;

    /**
     * @param $user
     */
    public function setUser($user)
    {
        $this->user = $user;
    }
}

当我尝试通过entityManager保存两个实体时,我得到一个例外。

$em = $this->getEntityManager();

$user = new TestUser();
$address = new TestAddress();
$address->setUser($user);

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

例外:

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

只保存两个实体的方法是“刷新”用户,然后保持并刷新地址。

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

问题:有没有办法在TestUser id上使用自动增量并使用一次刷新保存TestUser和TestAddress实体?

2 个答案:

答案 0 :(得分:0)

class TestAddress
{
    /**
     * @ORM\OneToOne(targetEntity="TestUser", cascade={"persist"})
     */
    private $user;

答案 1 :(得分:0)

我知道它甚至不是你问题的答案,但IMO你应该重新考虑这个模式选择的目的,当地址实体的ID必须对应于用户实体的ID。我不认为这是必要的,你可以通过在Address实体上使用单独的外键和主键字段来改善。

然而,您可以尝试的另一件事是使关系成双向,即在User对象上定义testAddress变量,然后向其添加相应的映射信息:

/**
 * @OneToOne(targetEntity="TestAddress", mappedBy="user", cascade={"persist"})
 */
private $testAddress;

然后您可能还需要在用户实体上创建setTestAddress()方法,并在那里显式设置TestAddress的用户对象:

public function setTestAddress($address)
{ 
  $address->setUser($this);
  $this->testAddress = $address;
}

然后您可以调用$ user-> setTestAddress($ address)并尝试仅刷新用户实体:

$user = new TestUser();
$address = new TestAddress();
$user->setTestAddress($address);
$em->persist($user);
$em->flush();

我不太熟悉doctrine持久化实体的顺序,但是让实体被TestUser实体持久化而不是相反(如建议的那样)用户应首先保留,而不是将其ID添加到它之前的地址甚至是持久的。

我没有测试代码,所以可能会有一些错误。