【问题标题】:CakePHP Delete with Multiple ConditionsCakePHP 删除多个条件
【发布时间】:2015-03-19 13:12:34
【问题描述】:

这快把我逼疯了。为什么 Cake 需要把简单的事情变得过于复杂..

我希望让 Cake 生成如下所示的 SQL。

我希望运行的 SQL 是

DELETE `ProductVouchers` 
FROM `product_vouchers` AS `ProductVouchers`   
WHERE `ProductVouchers`.`id` = 16 
AND `ProductVouchers`.`client_id` IS NULL; 

我正在像这样使用delete()

$this->ProductVouchers->delete([
    'ProductVouchers.id'=>$id,
    'ProductVouchers.client_id'=>"NULL"
]);

日志显示

DELETE `ProductVouchers` 
FROM `product_vouchers` AS `ProductVouchers`   
WHERE `ProductVouchers`.`id` IN (16, 'NULL')

尝试

$this->ProductVouchers->delete([
   'ProductVouchers.id'=>$id,
   'ProductVouchers.client_id'=>NULL
]);

日志显示

DELETE `ProductVouchers` 
FROM `product_vouchers` AS `ProductVouchers`   
WHERE `ProductVouchers`.`id` IN (16, NULL) 

尝试:

 $this->ProductVouchers->delete([
    'ProductVouchers.id'=>$id,
    'ProductVouchers.client_id IS NULL'
 ]);

日志没有显示更错误的内容!

编辑:

正如下面的答案中所指出的,delete() 方法不正确,因为它只接受主键作为整数。所以使用deleteAll()

 $this->ProductVouchers->deleteAll([       
   'ProductVouchers.id'=>$id,
   'ProductVouchers.client_id'=>'NULL'
 ]);

这也不会在日志中产生任何错误或任何错误。尝试:

 $this->ProductVouchers->deleteAll([
   'ProductVouchers.id'=>$id,
   'ProductVouchers.client_id'=>NULL
 ]);

这会产生...

 DELETE `ProductVouchers` 
 FROM `product_vouchers` AS `ProductVouchers`   
 WHERE `ProductVouchers`.`id` = (17)

哪一个是错误的和奇怪的(括号的意义是什么??)

【问题讨论】:

  • 为什么什么?我没有得到这个问题?
  • 更新了我的问题 - 抱歉不是很清楚。我沮丧的产物

标签: php cakephp cakephp-3.0


【解决方案1】:

Model::delete 需要一个 id

Delete 是一种按主键值删除一行的方法。 Model::delete 的方法签名不期望条件:

删除()公开

删除给定 ID 的记录。如果没有给出 ID,则使用当前 ID。成功时返回 true。

参数

整数|字符串 $id 可选 null - 要删除的记录 ID

boolean $cascade 可选 true

调用传递数组时的行为是它不会以某种方式工作(在这种情况下,条件数组的数组值被理解为 ids - 并用于查找 a 要删除的记录 - 最多删除一行)。

Model::deleteAll 需要条件

deleteAll是一种按条件删除行的方法:

/**
 * Deletes multiple model records based on a set of conditions.
 *
 * @param mixed $conditions Conditions to match
 * @param bool $cascade Set to true to delete records that depend on this record
 * @param bool $callbacks Run callbacks
 * @return bool True on success, false on failure
 * @link http://book.cakephp.org/2.0/en/models/deleting-data.html#deleteall
 */
    public function deleteAll($conditions, $cascade = true, $callbacks = false) {

对问题中逻辑的正确调用是:

$model->deleteAll(
    [
        'ProductVouchers.id' => 16, 
        'ProductVouchers.client_id' => null
    ],
    $cascade,
    $callbacks
);

这也不会在日志中产生任何错误或任何错误

使用$cascade true(默认)调用 deleteAll 意味着:

  • 查找所有符合条件的记录
  • 一一删除

如果没有找到符合条件的记录,则不会有删除语句。

这个条件片段:

'ProductVouchers.client_id'=>'NULL'

会生成这个sql:

WHERE ProductVouchers.client_id = 'NULL'

即它将返回 client_id 为字符串“NULL”的行 - 因此没有删除语句,因为有 no 行的 client_id 设置为字符串“NULL”。

既错误又奇怪(括号的意义是什么??)

实际上该语句是预期的如果有一条记录,该主键和client_id设置为null(在它之前将有一个select语句通过id和client_id值查找)。括号没有功能相关性,这两个语句是等价的:

DELETE FROM `product_vouchers` WHERE `ProductVouchers`.`id` = (17)
DELETE FROM `product_vouchers` WHERE `ProductVouchers`.`id` = 17

如何按条件删除?

要生成这个sql的等价物:

DELETE FROM `product_vouchers` AS `ProductVouchers`   
WHERE `ProductVouchers`.`id` = 16 
AND `ProductVouchers`.`client_id` IS NULL; 

只需禁用$cascade

$model->deleteAll(
    [
        'ProductVouchers.id' => 16, 
        'ProductVouchers.client_id' => null
    ],
    false # <- single delete statement please
);

【讨论】:

    【解决方案2】:

    只需阅读文档,delete method only takes the identifier in the first parameter 设计为整数。

    看起来 Cake 团队可能已经接受了数组格式,但只使用数组值提供给删除查询(因此每次都忽略键并使用标识符。)

    我相信您正在寻找the deleteAll method,它将接受您在问题中提供的自定义条件:

    $this->ProductVouchers->deleteAll(['ProductVouchers.id'=>$id,'ProductVouchers.client_id'=>"NULL"]);
    

    【讨论】:

    • 我已经阅读了文档并尝试了您的建议。公平点重新删除方法,但 deleteAll 也没有太大成功
    • @MikeMiller 你能用deleteAll编辑你的经验和日志吗?
    【解决方案3】:

    此问题与模型 ProductVouchers 模型中的 $belongsTo 变量有关。虽然设置了这一点,但如果不将 $cascade 参数设置为 false,我就无法将条件应用于外键,如下所示:

     $this->ProductVouchers->deleteAll([
       'ProductVouchers.id'=>$id,
       'ProductVouchers.client_id IS NULL'
     ],false);
    

    这会产生有效的 SQL

    DELETE `ProductVouchers` FROM `product_vouchers` AS `ProductVouchers`             
    LEFT JOIN `onepulse_dev`.`clients` AS `Client`
    ON (`ProductVouchers`.`client_id` = `Client`.`clients_id`)  
    WHERE `ProductVouchers`.`id` = 25 AND `ProductVouchers`.`client_id` IS NULL
    

    编辑:

    按照@AD7six 的综合回答删除不必要的连接。

     $this->ProductVouchers->deleteAll([
       'ProductVouchers.id'=>$id,
       'ProductVouchers.client_id'=>NULL
     ],false);
    

    【讨论】:

    • 对我来说足够清楚。感谢您的有用意见
    • 不需要的连接是它一直如何工作的产物 - 一种解决方法是在调用 deleteAll 之前取消绑定关联(或者通过改组关联属性的含义,例如在您的应用程序模型中创建 public function deleteAll(...) { $old = $this-&gt;belongsTo; $this-&gt;belongsTo = []; $return = parent::deleteAll(...); $this-&gt;belongsTo = $old; return $return; } - 在为自己测试和验证之后 - 我建议编辑你的答案以获得代码示例 - 使答案对其他读者更有用(无需提及我的昵称 - 不过感谢你的想法)。
    【解决方案4】:

    尝试关注:

    $id = 100;
    $conditions = array(
        'OR' => array(
            'ProductVouchers.id' => $id,
            'ProductVouchers.client_id IS NULL'
        )
    );
    
    $this->ProductVouchers->deleteAll($conditions);
    

    应创建以下 SQL 查询:

    SELECT `ProductVouchers`.`id` FROM `cakephp2`.`ProductVouchers` AS `product_vouchers` WHERE ((`ProductVouchers`.`id` = 100) OR (`ProductVouchers`.`client_id` IS NULL)) GROUP BY `ProductVouchers`.`id`
    DELETE `ProductVouchers` FROM `cakephp2`.`ProductVouchers` AS `product_vouchers` WHERE `ProductVouchers`.`id` IN (1, 8, 100)
    

    “IN (1, 8, 100)”是前面调用的 SELECT 语句的结果。

    【讨论】:

    • 问题中没有OR
    【解决方案5】:

    试试这个删除所有具有多个条件的

    $this->Model->deleteAll(array('Model.field_name'=>'field_value'));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-23
      相关资源
      最近更新 更多