首页 > 解决方案 > 删除相关行时将外部列设置为 NULL

问题描述

我有两个可选图片的用户(不要担心逻辑,名称已更改以保护无辜者):

CREATE TABLE users (
    id INT(10) NOT NULL AUTO_INCREMENT,
    first_name VARCHAR(255),
    last_name VARCHAR(255),
    first_picture_id INT(10) NULL DEFAULT NULL,
    second_picture_id INT(10) NULL DEFAULT NULL,
    PRIMARY KEY (id),
    CONSTRAINT FK_users_second_picture_id FOREIGN KEY (second_picture_id) REFERENCES pictures (id),
    CONSTRAINT FK_users_first_picture_id FOREIGN KEY (first_picture_id) REFERENCES pictures (id)
);

CREATE TABLE pictures (
    id INT(10) NOT NULL AUTO_INCREMENT,
    name VARCHAR(255) NOT NULL,
    path VARCHAR(255) NOT NULL,
    type VARCHAR(255) NOT NULL,
    PRIMARY KEY (id)
);

我以这种方式链接了我的模型(我希望那部分是正确的):

class User extends AppModel{
    public $belongsTo = array(
        'FirstPicture' => array(
            'className' => 'Picture',
            'foreignKey' => 'first_picture_id',
        ),
        'SecondPicture' => array(
            'className' => 'Picture',
            'foreignKey' => 'second_picture_id',
        ),
    );
}
class Picture extends AppModel{
    public $hasOne = array(
        'User',
    );
}

现在,当我删除任一图片时:

$this->FirstPicture->delete($this->request->data('FirstPicture.id'));

...我想将 set 中的相应列user设置为NULL.

ON DELETE SET NULL复制外键删除的 CakePHP 习语(如果有的话)是什么?

标签: cakephpcakephp-2.4cakephp-2.x

解决方案


CakePHP 2.x 中没有内置的功能可以自动执行此操作,您必须自己实现它。只要有可能,建议在您的数据库中使用实际的外键约束,但如果这不可能,那么您在这里真的没有太多选择。

beforeDelete在orafterDelete事件/回调中这样做应该很容易。如果您的数据库支持事务(并且您的应用程序使用它们 - 它们不会自动发生删除操作),那么beforeDelete建议您这样做,因为它可以轻松停止删除过程。如果没有事务,这将取决于您在错误情况下更喜欢什么,在没有删除关联记录的情况下将外键设为空 ( beforeDelete),或者使用非空外键 ( afterDelete) 删除关联记录。

这是一个简单的示例,您可以从关联的任一方执行此操作Picture

public function beforeDelete($cascade = true) {
    if (!parent::beforeDelete($cascade)) {
        return false;
    }

    $result = $this->User->updateAll(
        array('first_picture_id' => null),
        array('first_picture_id' => $this->getID())
    );
    if (!$result) {
        return false;
    }

    $result = $this->User->updateAll(
        array('second_picture_id' => null),
        array('second_picture_id' => $this->getID())
    );
    if (!$result) {
        return false;
    }

    return true;
}

User

public function __construct($id = false, $table = null, $ds = null)
{
    parent::__construct($id, $table, $ds);

    $this->FirstPicture->getEventManager()->attach(
        function () {
            return $this->updateAll(
                array('first_picture_id' => null),
                array('first_picture_id' => $this->FirstPicture->getID())
            );
        },
        'Model.beforeDelete'
    );

    $this->SecondPicture->getEventManager()->attach(
        function () {
            return $this->updateAll(
                array('second_picture_id' => null),
                array('second_picture_id' => $this->SecondPicture->getID())
            );
        },
        'Model.beforeDelete'
    );
}

推荐阅读