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

如何优化Eloquent中基于Services表的分类-企业关联查询以支持约束?

最优实现方案

问题核心

你之前用Attribute定义的"关联"本质是返回查询构造器,并非Laravel Eloquent的关联关系实例,因此无法使用whereHas这类关联查询方法。需要将模型间的关系用Eloquent原生关联方法定义,才能支持嵌套筛选、排序等操作。

步骤1:修正模型关联定义

根据你的业务逻辑,模型间的关系是:

  • 分类(Category)与企业(Company):多对多,通过services表作为中间表
  • 企业(Company)与服务(Service):一对多
  • 服务(Service)与评论(Review):一对多

修改CategoryModel.php的关联方法

替换原来的Attribute实现为多对多关联:

// CategoryModel.php
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

public function companies(): BelongsToMany
{
    // 参数:关联模型、中间表名、当前模型外键、关联模型外键
    return $this->belongsToMany(CompanyModel::class, 'services', 'category_id', 'company_id');
}

补充其他模型的关联

// CompanyModel.php
use Illuminate\Database\Eloquent\Relations\HasMany;

public function services(): HasMany
{
    return $this->hasMany(ServiceModel::class, 'company_id');
}
// ServiceModel.php
use Illuminate\Database\Eloquent\Relations\HasMany;

public function reviews(): HasMany
{
    return $this->hasMany(ReviewModel::class, 'service_id');
}

步骤2:修复筛选作用域

现在关联已合法,可以直接通过嵌套whereHas实现评论筛选:

// CategoryModel.php
public function scopeHasReviews($query)
{
    // 多层关联筛选:分类 -> 企业 -> 服务 -> 评论
    $query->whereHas('companies.services.reviews');
}

扩展:支持复杂筛选与排序

如果需要按评论评分筛选或排序,可直接基于关联链扩展:

// CategoryModel.php
// 筛选包含评分≥4的评论的分类
public function scopeWithHighRatedReviews($query, $minRating = 4)
{
    $query->whereHas('companies.services.reviews', function ($q) use ($minRating) {
        $q->where('rating', '>=', $minRating);
    })
    // 预加载平均评分并排序
    ->withAvg(['companies.services.reviews' => function ($q) {
        $q->selectRaw('avg(rating) as avg_rating');
    }], 'avg_rating')
    ->orderBy('avg_rating', 'desc');
}

为什么原方案无效?

Attribute是Eloquent的属性访问器,仅用于自定义模型属性的读取逻辑,返回的是查询构造器而非关联关系实例。而whereHas、with等方法依赖Eloquent关联关系提供的查询绑定能力,必须用belongsToMany/hasMany等官方关联方法定义关系才能生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 15:15:40