克隆的实体导致重复的INSERT语句 [英] Cloned entity leads to duplicated INSERT statements

查看:95
本文介绍了克隆的实体导致重复的INSERT语句的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实施克隆页面上列出实体的动作(电路)。工作流程如下:

I am trying to implement a "Clone" action on a page listing entities ("Circuits"). The workflow is the following:


  1. 用户选择一个实体,然后选择克隆。下拉菜单中的操作

  2. 将触发CircuitsController :: indexAction方法,将用户重定向到CircuitsController :: editAction页面,并传递Circuit的ID和GET参数 $ is_clone = true;

  3. 用户修改了他想要的内容,然后提交

  4. CircuitsController :: editAction方法看到了提出了一个克隆请求,克隆了Circuit实体,将其持久化然后刷新EntityManager。

  1. user selects an entity then selects the "Clone" action in a dropdown
  2. 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;
  3. user modifies whatever he wants, then submits
  4. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆