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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:17:42