Laravel Eloquent 级联删除

Posted

技术标签:

【中文标题】Laravel Eloquent 级联删除【英文标题】:Laravel Eloquent Cascading Deletes 【发布时间】:2014-05-07 12:53:31 【问题描述】:

我正在使用 Laravel 4.1 并正在尝试级联删除。我这样做是因为一些删除方法会删除存储在 S3 上的关联资产,因此依赖 DB 级联删除是不合适的。

假设我有一个 Entry 模型,它本身有一个图像和许多相关的 Option,它们也有如下所示的图像(为了简洁而减少)。

class Entry extends Eloquent 
    public function image()
    
        return $this->morphOne('Image', 'imageable');
    

    public function options()
    
        return $this->hasMany('Option');
    

    protected static function boot() 
        parent::boot();

        static::deleting(function($entry) 
            $image = $entry->image;
            if($image !== null) 
                $image->delete();
            

            $entry->options()->delete()
            //Option::where('entry_id', $entry->id)->delete(); This also doesn't work
        );
    


class Option extends Eloquent 

    public function entry()
    
        return $this->belongsTo('Entry');
    

    public function image()
    
         return $this->morphOne('Image', 'imageable');
    

    protected static function boot() 
        parent::boot();

        static::deleting(function($option) 
            Log::info('Trying to delete an option object');
            $image = $option->image;

            if($image !== null) 
                $image->delete();
            
        );
    

注意:我正在按照this answer 中的建议进行删除。

当我调用 $entry->delete() 时,它将删除图像和条目本身,但是永远不会在选项上调用删除处理程序(我没有看到它输出到日志)。但是,如果我在条目删除功能中使用以下内容,一切正常。

foreach($entry->options as $option) 
    $option->delete();

为什么 $entry->options()->delete() 不起作用?这是 Laravel 中的错误还是我犯了一个错误。

【问题讨论】:

【参考方案1】:
class Entry extends Eloquent 
    public function image()
    
        return $this->morphOne('Image', 'imageable');
    

    public function options()
    
        return $this->hasMany('Option');
    

    protected static function boot() 
        parent::boot();

        static::deleting(function($entry) 
            $image = $entry->image;
            if($image !== null) 
                $image->delete();
            

            $entry->options->each(function($option) 
                $option->delete();
            );
            //Option::where('entry_id', $entry->id)->delete(); This also doesn't work
        );
    

您可以使用“每个” http://laravel.com/docs/eloquent#collections

【讨论】:

我已经尝试过使用每个,但是我认为它与使用 foreach 没有太大不同,您仍然需要遍历每个对象。我更好奇为什么 $entry->options()->delete 不起作用【参考方案2】:

有一个很好的包可以将其作为上述引导方法的替代方法并用于软删除。

写: https://medium.com/asked-io/cascading-softdeletes-with-laravel-5-a1a9335a5b4d

Laravel/Lumen 软级联删除和恢复 https://github.com/Askedio/laravel-soft-cascade

【讨论】:

以上是关于Laravel Eloquent 级联删除的主要内容,如果未能解决你的问题,请参考以下文章

php Laravel 5.8级联删除

Laravel:级联删除模型,如果没有其他模型共享它

雄辩的关系和数据库约束?

sql级联更新和级联删除不起作用

如何理解access设置中的“级联更新”和“级联删除”?

SQL 级联删除与级联更新的方法