You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Eloquent:如何获取已修改模型的原始关联关系?

如何优雅获取Eloquent模型保存前的原始分类?

这个场景在Eloquent模型关联更新里太常见了!其实有几种优雅的方式可以拿到保存前的原始分类,我给你整理了几个实用方案:

方法一:直接使用getOriginal()方法(最直接)

Eloquent模型自带的getOriginal()方法可以返回模型保存前的原始属性数组,我们可以直接从中取出旧的category_id,再查询对应的分类模型:

class Item extends Model { 
    protected static function boot() { 
        parent::boot(); 
        static::saved(function (Item $item) { 
            if ($item->wasChanged('category_id')) { 
                // 更新当前关联的分类计数
                $item->category->updateItemCount(); 
                
                // 获取原始分类ID并查询对应模型
                $originalCategoryId = $item->getOriginal('category_id');
                $originalCategory = Category::find($originalCategoryId);
                
                // 确保原始分类存在再更新计数
                if ($originalCategory) {
                    $originalCategory->updateItemCount();
                }
            } 
        }); 
    } 
    // ... 其他关联方法
}

这个方法的优势是简单直接,不需要额外的前置操作,完全利用Eloquent自带的方法实现。

方法二:在saving回调中提前缓存原始分类

如果担心在saved回调中重复查询(虽然这里其实只查一次),可以在保存前的saving回调里提前把原始分类缓存到模型的临时属性中,后续直接使用:

class Item extends Model { 
    protected static function boot() { 
        parent::boot(); 
        
        // 保存前缓存原始分类
        static::saving(function (Item $item) { 
            // 判断category_id是否被修改
            if ($item->isDirty('category_id')) { 
                $originalCategoryId = $item->getOriginal('category_id');
                $item->originalCategory = Category::find($originalCategoryId);
            } 
        });
        
        static::saved(function (Item $item) { 
            if ($item->wasChanged('category_id')) { 
                $item->category->updateItemCount(); 
                // 直接使用提前缓存的原始分类
                if (isset($item->originalCategory)) {
                    $item->originalCategory->updateItemCount();
                }
            } 
        }); 
    } 
    // ... 其他关联方法
}

这种方式逻辑更清晰,把“获取原始数据”和“执行更新”的步骤分开,可读性更好。

额外优化:用增量更新替代全量计数

你当前的updateItemCount()方法每次都执行count()查询,数据量大的时候会影响性能。其实可以改成增量/减量的方式,效率更高:

首先修改Category模型的方法:

class Category extends Model { 
    // 新增增量方法
    public function incrementItemCount() {
        $this->increment('item_count');
    }
    
    // 新增减量方法
    public function decrementItemCount() {
        $this->decrement('item_count');
    }
    
    // 保留原方法,用于初始化或修复计数时使用
    public function updateItemCount() { 
        $this->item_count = $this->items()->count(); 
        $this->save(); 
    } 
    // ... 其他关联方法
}

然后在Item的saved回调中替换成增量操作:

static::saved(function (Item $item) { 
    if ($item->wasChanged('category_id')) { 
        $item->category->incrementItemCount(); 
        
        $originalCategoryId = $item->getOriginal('category_id');
        $originalCategory = Category::find($originalCategoryId);
        
        if ($originalCategory) {
            $originalCategory->decrementItemCount();
        }
    } 
});

这样每次分类变更只需要执行两次简单的增量/减量SQL,比全量count高效得多。

内容的提问来源于stack exchange,提问作者bijiDango

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:50:49