CakePHP 3.x - 如何在单个事务中删除多个表中的记录?

时间:2016-08-13 10:34:00

标签: cakephp orm transactions cakephp-3.x

如何修改下面的代码以确保两个删除都将在CakePHP 3.x中的一个事务中进行?

// In initialize:
$this->loadModel('A');

// In the delete function: 
$elem=$this->A->get($id);
$rec=$elem->...; 
$this->A->delete($elem);

$this->loadModel('B');
$this->B->deleteAll(['B.rec'=>$rec]);

2 个答案:

答案 0 :(得分:2)

对于关联表

如果您的表彼此关联,您可以使用dependent选项来定义自动删除相关记录的关联。默认情况下,这将发生在事务中。

 $this->hasMany('B', [
     'dependent' => true,
     // ...
 ]);

另见

对于非关联表/非依赖关联

这就是\Cake\Datasource\ConnectionInterface::transactional()方法,分别是\Cake\Database\Connection::begin()commit()rollback()方法。

使用transactional()是一种更简单的方法,在传递的回调中完成的所有操作都在事务中运行。

来自文档的引用:

  

交易方法将执行以下操作:

     
      
  • 致电begin
  •   
  • 调用提供的闭包。
  •   
  • 如果闭包引发异常,则会发出回滚。将重新抛出原始异常。
  •   
  • 如果闭包返回false,则会发出回滚。
  •   
  • 如果闭包执行成功,将提交交易。
  •   
  

<强>返回

     

mixed   回调的返回值。

因此,将代码包装在回调中,并确保评估Table::delete()返回值并在必要时返回false,以便在删除操作失败时发出回滚。 / p>

$connection = \Cake\Datasource\ConnectionManager::get('default');
$result = $connection->transactional(function ($connection) use ($id) {
    $elem = $this->A->get($id);
    $rec = $elem->/*...*/;
    if (!$this->A->delete($elem, ['atomic' => false])) {
        return false;
    }

    $this->loadModel('B');
    $this->B->deleteAll(['B.rec' => $rec]);

    return true;
});

请注意,在这种情况下应禁用atomic选项,以便delete()不会尝试自行创建事务。

还应该注意的是,如果您的代码需要触发该事件,那么手动将delete()调用内部事务会导致Model.afterDeleteCommit事件被触发那么你必须自己做。

另见

答案 1 :(得分:0)

 $this->Model->hasMany('TrModels', [ 'bindingKey' => 'transaction column', 'foreignKey' => 'transaction column', 'joinType' => 'LEFT', 'dependent' => true, 'cascadeCallbacks' => true,]);

          $deleteINQ = $this->Models->get($id);//Parrent id
         $this->Models->delete($deleteINQ);