我有一个复杂/嵌套的对象,通过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
只保存,如果它还不存在?
解决方案是在保存引用实体之前保留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();