我有一个由Zend\Form
数据自动水合创建的复杂/嵌套对象。现在我想用Doctrine 2保存它。最好的情况是在顶层只有一个persist(...)
和一个flush(...)
调用。但它不会像这样工作。所以现在我有以下问题:
有对象User
和Order
。关系为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
不存在:创建Order
和User
。
但如果User
存在,则会发生错误:
使用params [“myusername”,“member”,null,null]执行'INSERT INTO用户(用户名,角色,创建,更新)VALUES(?,?,?,?)'时发生异常:
SQLSTATE [23000]:完整性约束违规:1062重复条目'username_UNIQUE'重复输入'myusername'
如何处理保存,User
只保存,如果它还不存在?
答案 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();