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
相关产品推荐
相关产品推荐

