如何在事务期间运行查询影响实体

时间:2017-08-17 10:09:06

标签: php symfony doctrine-orm

我正在尝试遍历某些实体并更新step_order列,然后从该列中减去一个值。请看以下示例:

  1. 从这些实体开始

    ID | step_order
    1  | 1
    2  | 2
    3  | 3
    4  | 4
    
  2. 更改订单

    ID | step_order
    1  | 6
    2  | 5
    3  | 7
    4  | 8
    
  3. 从订单中减去4,将值恢复为1

    ID | step_order
    1  | 2
    2  | 1
    3  | 3
    4  | 4
    
  4. 这是我删除了无关部分的代码:

    在经理

    $nextOrder = $this->stepRepo->findNextOrder($maintenanceId);
    $steps = [];
    foreach ($order as $o => $stepId) {
        $step = $this->getStep($stepId);
        $steps[] = $step;
    }
    $this->em->beginTransaction();
    foreach ($steps as $o => $step) {
        $step->setStepOrder($nextOrder + $o);
        $this->em->persist($step);
    }
    $this->stepRepo->subtractOrder($maintenanceId, $nextOrder - 1);
    $this->em->commit();
    $this->em->flush();
    
    public function getStep($id)
    {
        return $this->stepRepo->find($id);
    }
    

    在stepRepo中

    public function subtractOrder($maintenanceId, $amount)
    {
        $maintenanceId = (int) $maintenanceId;
        $qb = $this->createQueryBuilder('s');
        $qb->update()
            ->set('s.stepOrder', 's.stepOrder - :amount')
            ->where('s.maintenanceId = :maintenanceId')
            ->setParameter('amount', $amount)
            ->setParameter('maintenanceId', $maintenanceId);
        $result = $qb->getQuery()->execute();
        return $result;
    }
    

    我期望发生的事情如下:

    1. 选择MAX(step_order)
    2. 开始交易
    3. 更新每个实体的step_order
    4. 运行查询更新所有step_orders = step_order - MAX(step_order)
    5. 提交
    6. 发生了什么:

      1. 选择MAX(step_order)
      2. 开始交易
      3. 运行查询更新所有step_orders = step_order - MAX(step_order)
      4. 提交
      5. 以下是symfony探查器的输出:

        SELECT MAX(l0_.step_order) AS sclr_0 FROM lsp_maintenance_step l0_ WHERE l0_.maintenance_id = ?
        Parameters: ['1']
        
        "START TRANSACTION"
        Parameters: { }
        
        UPDATE lsp_maintenance_step SET step_order = step_order - ? WHERE maintenance_id = ?
        Parameters: [4, 1]
        

        这是MySQL错误:

        An exception occurred while executing 'UPDATE lsp_maintenance_step SET step_order = step_order - ? WHERE maintenance_id = ?' with params [4, 1]:\n\nSQLSTATE[22003]: Numeric value out of range: 1690 BIGINT UNSIGNED value is out of range in '(`toolbox`.`lsp_maintenance_step`.`step_order` - 4)'
        

        错误是正确的,因为从任何实体中减去4会使步骤顺序为0或更小,这是不正确的。

        为什么在更新实体之前,doctrine会运行最后一个UPDATE

1 个答案:

答案 0 :(得分:1)

  

为什么在更新实体之前,doctrine会运行最后一个UPDATE

经过一番挖掘后,我发现在flush()上调用EntityManager时会提交实体,而execute()会立即运行。

为了解决这个问题,我使用transaction nesting,其中实体在子事务中提交,并且在主事务中调用UPDATE

$this->em->beginTransaction();
try {
    $this->em->beginTransaction();
    try {
        foreach ($steps as $o => $step) {
            $step->setStepOrder($nextOrder + $o);
            $this->em->persist($step);
        }
        $this->em->flush();
    } catch (\Exception $e) {
        $this->em->rollback();
        throw $e;
    }
    $this->stepRepo->subtractOrder($maintenanceId, $nextOrder - 1);
    $this->em->flush();
    foreach ($steps as $step) {
        $this->em->refresh($step);
    }
} catch (\Exception $e) {
    $this->em->rollback();
}