如果实体不存在,如何只保留一个关系的一端而另一端只保留?

时间:2017-10-17 17:52:15

标签: doctrine-orm doctrine one-to-many many-to-one persist

我有一个由Zend\Form数据自动水合创建的复杂/嵌套对象。现在我想用Doctrine 2保存它。最好的情况是在顶层只有一个persist(...)和一个flush(...)调用。但它不会像这样工作。所以现在我有以下问题:

有对象UserOrder。关系为1:n(因此,1 User具有n Order s)。 User已经存在。当User Joe尝试保存多个Order(例如其第二个订单)时,会发生错误:

  

通过关系'... \ Order#user'找到了一个新实体,该关系未配置为级联实体的持久操作:... \ User @ 000000003ba4559d000000005be8d831。要解决此问题:在此未知实体上显式调用EntityManager#persist()或在映射中配置级联持久保存此关联,例如@ManyToOne(..,cascade = {“persist”})。如果您无法找出导致问题的实体,请执行'... \ User #__ toString()'以获取线索。

好吧,我添加了cascade={"persist"}(虽然这里没有意义,但无论如何,只是为了尝试一下):

class Order
{
    ...
    /**
     * @var User
     *
     * @ORM\ManyToOne(targetEntity="User", cascade={"persist"})
     */
    protected $user;
    ...
}

现在它可行,如果给定的User不存在:创建OrderUser

但如果User存在,则会发生错误:

  

使用params [“myusername”,“member”,null,null]执行'INSERT INTO用户(用户名,角色,创建,更新)VALUES(?,?,?,?)'时发生异常:

     

SQLSTATE [23000]:完整性约束违规:1062重复条目'username_UNIQUE'重复输入'myusername'

如何处理保存,User只保存,如果它还不存在?

1 个答案:

答案 0 :(得分:0)

解决方案是在保存引用实体之前保留User。如果它尚不存在,则需要先创建(persist ed和flush ed):

$user = $this->entityManager->getRepository(User::class)->findOneBy(
    ['username' => $dataObject->getUser()->getUsername()]
);
if (! $user) {
    $this->entityManager->persist($dataObject->getUser());
    $this->entityManager->flush($dataObject->getUser());
    $user = $this->entityManager->getRepository(User::class)->findOneBy(
        ['username' => $dataObject->getUser()->getUsername()]
    );
}
$dataObject->setUser($user);

$this->entityManager->persist($dataObject);
$this->entityManager->flush();

不应使用cascade={"persist"},因为在这种情况下实际上没有意义。

修改

甚至更容易:

$user = $this->entityManager->getRepository(User::class)->findOneBy(
    ['username' => $dataObject->getUser()->getUsername()]
);
if ($user) {
    $dataObject->setUser($user);
} else {
    $this->entityManager->persist($dataObject->getUser());
}

$this->entityManager->persist($dataObject);
$this->entityManager->flush();