克隆的实体导致重复的INSERT语句 [英] Cloned entity leads to duplicated INSERT statements
问题描述
我正在尝试实施克隆页面上列出实体的动作(电路)。工作流程如下:
I am trying to implement a "Clone" action on a page listing entities ("Circuits"). The workflow is the following:
- 用户选择一个实体,然后选择克隆。下拉菜单中的操作
- 将触发CircuitsController :: indexAction方法,将用户重定向到CircuitsController :: editAction页面,并传递Circuit的ID和GET参数
$ is_clone = true;
- 用户修改了他想要的内容,然后提交
- CircuitsController :: editAction方法看到了提出了一个克隆请求,克隆了Circuit实体,将其持久化然后刷新EntityManager。
- user selects an entity then selects the "Clone" action in a dropdown
- the CircuitsController::indexAction method is fired, redirects the user to the CircuitsController::editAction page and pass along the Circuit's ID and a GET parameter
$is_clone = true;
- user modifies whatever he wants, then submits
- the CircuitsController::editAction method sees that a clone request has been made, clones the Circuit entity, persist it then flush the EntityManager.
我的问题是,当EntityManager :: flush方法时会被调用,执行两个严格相同的INSERT查询,从而导致回滚并且没有新的电路持久。
My issue here is that when the EntityManager::flush method is called, two strictly identical INSERT queries are performed, thus leading to a rollback and no new circuit persisted.
这是 CircuitsController :: indexAction 中的代码部分重定向的em>
Here is the portion of code from the CircuitsController::indexAction that redirects:
case 'duplicate':
$this->denyAccessUnlessGranted('ROLE_NETWORK', null, 'Insufficient rights to perform selected action.');
if (count($formData['circuits']) != 1) {
throw new \RuntimeException('Cannot duplicate more than one item.');
}
/* 'circuits' key points to an array of circuits */
$circuit = $formData['circuits'][0];
return $this->redirect($this->generateUrl('net_dev_web_circuits_edit',
['id' => $circuit->getId(),
'type' => $type,
'clone' => true]));
我的 CircuitsController :: editAction :
public function editAction(Request $request, Circuit $circuit, $type = 'mnms') {
$this->denyAccessUnlessGranted('ROLE_NETWORK', null, 'Insufficient rights to perform selected action.');
$em = $this->getDoctrine()->getManager();
$clone = $request->query->get('clone');
$circuitForm = $this->buildCircuitsForm($circuit, $type, ['is_clone' => $clone]);
if (empty($clone)) {
$lcmForm = $this->generateLcmForm($em, $circuit);
}
else {
$lcmForm = null;
}
if ($request->isMethod('POST')) {
if ($circuitForm->handleRequest($request)->isValid()) {
if ($clone) {
$em->detach($circuit);
$circuit = clone $circuit;
$em->persist($circuit);
$endPointRepo = $em->getRepository('NetDevCoreBundle:EndPoint');
$mnms = $circuit->getMnmsCircuit();
$endPoints = $endPointRepo->findByCircuit($mnms);
foreach ($endPoints as $endPoint) {
$device = $endPoint->getDevice(); /* @var $device Device */
$defaultEndPoint = (new EndPoint())
->setCircuit($circuit)
->setDevice($device)
->setSite($endPoint->getSite())
;
$device->addCircuit($circuit);
$em->persist($defaultEndPoint);
}
}
$em->flush();
$request->getSession()->getFlashBag()->add('notice', 'Circuit saved');
return $this->redirect($this->generateUrl('net_dev_web_circuits_edit', array('type' => $type,
'id' => $circuit->getId())));
}
/* [.. unrelated code (I hope) to get the edit form ..] */
}
以下是我实体的 __ clone 方法:
public function __clone() {
if ($this->id) {
$this->id = null;
$this->listenPops = new ArrayCollection();
$this->endPoints = new ArrayCollection();
}
}
最后,两个发出的SQL语句:
And finally, the two issued SQL statements:
#20 0.29 ms:
"START TRANSACTION"
Parameters: [null]
#21 0.29 ms:
INSERT INTO Circuit (
two_way, circuit_name, circuit_type,
mtu, port_bindings, user_enable,
bandwidth, tierLevel, translate,
crossconnect, header_compression,
padding_removal, untag_enable, landside_tx_duplicate_enable,
landside_tx_duplicate_vlan_id,
priority, trunk_force_mask, connection_number,
aptUserVlanIds, user_max_age, validationDate,
synchronizationDate, updatedAt,
macAddresses, vlan_id, mnms_circuit,
parent_route, customer
)
VALUES
(
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)
Parameters: { 1: 1, 2: MNMS_Tier1_ZZZ_XX_3171, 3: mnms, 4: 23, 5: 1, 6: 1, 7: 100, 8: 0, 9: 0, 10: '', 11: 0, 12: 0, 13: 0, 14: 0, 15: 0, 16: 1, 17: 0, 18: 1, 19: 'a:4:{i:1;N;i:2;N;i:3;N;i:4;N;}', 20: null, 21: '2015-08-19 11:33:42', 22: null, 23: '2015-09-07 18:48:37', 24: 'a:0:{}', 25: 233, 26: null, 27: 13, 28: 64 }
#22 0.00 ms:
INSERT INTO Circuit (
two_way, circuit_name, circuit_type,
mtu, port_bindings, user_enable,
bandwidth, tierLevel, translate,
crossconnect, header_compression,
padding_removal, untag_enable, landside_tx_duplicate_enable,
landside_tx_duplicate_vlan_id,
priority, trunk_force_mask, connection_number,
aptUserVlanIds, user_max_age, validationDate,
synchronizationDate, updatedAt,
macAddresses, vlan_id, mnms_circuit,
parent_route, customer
)
VALUES
(
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)
Parameters: { 1: 1, 2: MNMS_Tier1_ZZZ_XX_3171, 3: mnms, 4: 23, 5: 1, 6: 1, 7: 100, 8: 0, 9: 0, 10: '', 11: 0, 12: 0, 13: 0, 14: 0, 15: 0, 16: 1, 17: 0, 18: 1, 19: 'a:4:{i:1;N;i:2;N;i:3;N;i:4;N;}', 20: null, 21: '2015-08-19 11:33:42', 22: null, 23: '2015-09-07 18:48:37', 24: 'a:0:{}', 25: 233, 26: null, 27: 13, 28: 64 }
#23 3.96 ms
"ROLLBACK"
Parameters: [null]
我一直在摆弄,但无济于事。我想知道这是否不是由Doctrine尝试保留新克隆的实体 AND 所引起的,但这是作为模板使用的,但是我不知道如何(证明)这一点。
I have been fiddling around with that but to no avail. I am wondering if this would not be caused by Doctrine trying to persist the newly cloned Entity AND the one used as a template but I have no idea how I could (dis)prove that.
任何帮助将不胜感激。
感谢@user2268997的评论,我现在知道第二个INSERT引用了模板 ;电路。 Doctrine也会尝试更新它,这不是我想要的(我需要保持原始数据不变)。我能告诉教义不要更新原始实体的任何方法吗?
Thanks to @user2268997's comment, I now know that the second INSERT refers to the "template" circuit. Doctrine tries to update it as well, which is not what I want (I need the original data to be left unchanged). Any way I can tell Doctrine not to update the original entity ?
推荐答案
因为我能够弄清楚以前的实体是导致重复插入(感谢 @ user2268997 ),我已经研究出一种方法来告诉教义不要对它进行任何操作。
这是结果代码:
Since I was able to figure out that the former entity was causing the duplicate insert (thanks to @user2268997), I've looked into a way to tell Doctrine not to perform anything on it. Here's the resulting code:
if ($clone) {
$clonedCircuit = clone $circuit;
/* Here's the "fix" */
$em->refresh($circuit);
$em->detach($clonedCircuit);
$em->persist($clonedCircuit);
$em->flush();
/* [...] */
}
$circuit = $clonedCircuit;
电路已正确克隆并持久存在,与其他实体的关系也似乎正确。
The Circuit is correctly cloned and persisted, and relations with other entities seem correct as well.
这篇关于克隆的实体导致重复的INSERT语句的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!