删除相关行时将外列设置为 NULL

Set foreign column to NULL when related row is deleted

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

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'));

...我想把user中对应的列设为NULL.

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

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

beforeDeleteafterDelete events/callbacks 中做到这一点应该很容易。如果您的数据库支持事务(并且您的应用程序使用它们 - 它们不会自动发生删除操作),那么建议使用 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'
    );
}