Laravel模型中优雅高效查询分类-子分类关联无效的记录
解决方案:高效检索存在无效分类-子分类关联的Record
我来帮你实现这个需求,我们可以通过给Record模型添加**全局作用域(Scope)**来优雅且高效地完成查询,完全不需要在控制器里做循环遍历。所有判断逻辑都在数据库层面完成,能保证查询的性能。
步骤1:修改Record模型,添加自定义Scope
直接在你的Record模型中添加以下自定义Scope方法,它会封装三类无效关联的判断逻辑:
use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Facades\DB; class Record extends Model { public function category() { return $this->belongsTo(Category::class); } public function subcategory() { return $this->belongsTo(Subcategory::class); } /** * 自定义Scope:检索存在无效分类-子分类关联的记录 */ public function scopeWithInvalidCategorySubcategoryRelation(Builder $query) { return $query->where(function ($q) { // 情况a:Record同时关联Category和Subcategory,但子分类不属于该分类 $q->whereNotNull('category_id') ->whereNotNull('subcategory_id') ->whereDoesntHave('category.subcategories', function ($subQ) { $subQ->where('subcategories.id', '=', DB::raw('records.subcategory_id')); }); })->orWhere(function ($q) { // 情况b:Record关联了Category但未关联Subcategory,且该Category存在子分类 $q->whereNotNull('category_id') ->whereNull('subcategory_id') ->whereHas('category.subcategories'); })->orWhere(function ($q) { // 情况c:Record同时关联Category和Subcategory,但该Category本身不存在Subcategory $q->whereNotNull('category_id') ->whereNotNull('subcategory_id') ->whereDoesntHave('category.subcategories'); }); } }
逻辑说明
每个无效情况对应的查询逻辑都经过了性能优化:
- 情况a:通过
whereDoesntHave检查当前记录的分类下是否不存在对应的子分类,用子查询直接匹配关联关系,避免冗余数据加载。 - 情况b:用
whereHas快速判断分类是否存在子分类,同时结合subcategory_id为null的条件筛选无效记录。 - 情况c:同样利用
whereDoesntHave判断分类无下属子分类,但记录却关联了子分类,直接标记为无效。
步骤2:控制器中调用
现在你可以完全按照预期的方式调用,一行代码就能获取所有无效记录:
// 获取所有存在无效分类-子分类关联的Record $invalidRecords = Record::withInvalidCategorySubcategoryRelation()->get();
可选优化:用Join替代关联查询
如果你的category_subcategory表有合理的联合索引,也可以用左连接的方式替换部分whereHas逻辑,在某些数据库环境下可能会有更优的性能,比如情况a的替代写法:
$q->whereNotNull('category_id') ->whereNotNull('subcategory_id') ->leftJoin('category_subcategory', function ($join) { $join->on('category_subcategory.category_id', '=', 'records.category_id') ->on('category_subcategory.subcategory_id', '=', 'records.subcategory_id'); }) ->whereNull('category_subcategory.id');
你可以根据自己的数据库实际情况选择合适的写法。
内容的提问来源于stack exchange,提问作者timitalia
相关产品推荐
相关产品推荐

