Cakephp 3按关联数据删除过滤

时间:2016-08-23 16:39:06

标签: mysql cakephp cakephp-3.0

在CakePHP 3中,假设我要删除所有部门,其中员工已命名为" John" (部门有很多员工,员工属于部门

最简单的方法是过滤所有这些部门,并在foreach循环中逐个删除它们:

$departments = $this->Departments->find()
    ->matching('Employees', function ($q) {
        return $q->where(['Employees.name' => 'John']);
    })
    ->all();

foreach ($departments as $department) {
    $this->Departments->delete($department);
}

这将导致一个SELECT查询加上每个记录的一个DELETE查询。我更喜欢只有一个查询由数据库发送和执行。像这样:

DELETE Departments 
FROM departments Departments 
INNER JOIN employees Employees  ON 
    Employees.department_id = Departments.id 
    AND Employees.name = 'John';

阅读文档我找到三种删除记录的方法:

使用CakePHP 3和ORM是否有一种优雅的方式来获取我的查询?

2 个答案:

答案 0 :(得分:0)

deleteAll只是一个环绕

$this->Departments->query()
   ->delete()
   ->where([...])
   ->execute();

所以尽管如此,以类似的方式,我们可以这样做:

$departments = $this->Departments->query()
    ->delete()
    ->matching('Employees', function ($q) {
        return $q->where(['Employees.name' => 'John']);
    })
    ->execute();

但在这种情况下,您会注意到匹配条件被忽略。我看到有一个关于那个

的开放ticket

如果您只想使用两个查询,则可以执行查询以检索所有ID并在第二个查询中删除所有ID:

$departments_ids = $this->Departments->find()
    ->select(['id'])
    ->matching('Employees', function ($q) {
        return $q->where(['Employees.name' => 'John']);
    })
    ->toArray();

$this->Departments->deleteAll(['id' => $departments_ids ]);

导致类似:

DELETE FROM departments WHERE id IN
(
    // id list here
)

另一个解决方案可能是在子查询中转换内连接。实际上,您希望删除几乎所有名为John的员工的部门。

$employees = $this->Departments->Employees->find()
    ->select(['department_id'])
    ->distinct()
    ->where(['Employees.name' => 'John']);

$departments = $this->Departments->query()
    ->delete()
    ->where(['id IN' => $employees])
    ->execute();

答案 1 :(得分:0)

两件事:

第一:我建议的情况不正确

我的实际情况要复杂得多,所以我用众所周知的员工部门案例做了一个例子。我犯了一个错误:我需要的是删除属于某个部门的所有员工。我想从相关表上的基于表的con条件中删除数据。

实际上,你不能删除有一个名叫约翰的员工的部门,因为部门不是空的,那就是约翰! :d

这样的事情:

-- Create structures
CREATE TABLE IF NOT EXISTS departments (
  id int(11) NOT NULL AUTO_INCREMENT,
  name varchar(45) NOT NULL,
  PRIMARY KEY (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=4 ;

CREATE TABLE IF NOT EXISTS employees (
  id int(11) NOT NULL AUTO_INCREMENT,
  department_id int(11) NOT NULL,
  name varchar(45) NOT NULL,
  PRIMARY KEY (id),
  KEY fk_employees_department_idx (department_id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;

ALTER TABLE employees
  ADD CONSTRAINT fk_employees_departments FOREIGN KEY (department_id) REFERENCES departments (id) ON DELETE NO ACTION ON UPDATE NO ACTION;


-- Populate some data
INSERT INTO departments (id, name) VALUES
(1, 'Sales'),
(2, 'TI'),
(3, 'HHRR');

INSERT INTO employees (id, department_id, name) VALUES
(1, 1, 'John'),
(2, 1, 'Mary'),
(3, 2, 'Mark'),
(4, 3, 'Lorenzo');


-- Delete all employees that belong to the TI department (Mark should be removed)
DELETE emp FROM employees emp
INNER JOIN departments dep ON emp.department_id = dep.id AND dep.name = 'TI';

第二:您可以轻松地在CakePHP中执行此操作

您可以获得与上一个查询相同的结果:

    $departments = $this->Employees->Departments->find()
        ->select(['Departments.id'])
        ->where(['Departments.name' => 'TI']);
    $this->Employees->deleteAll(['Employees.department_id IN' => $departments]);

生成的mysql查询将是:

DELETE FROM employees WHERE department_id in 
(SELECT Departments.id AS `Departments__id` 
FROM departments Departments 
WHERE Departments.name = 'TI')

......这是正确的,而且易于理解。 @arilia,你用第一个答案指出了这个方向。对不起,请小心。