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

Laravel多外键Pivot表按多条件筛选关联影院实现方法

三表多对多关联下按双条件筛选影院数据实现方案

现有结构说明

当前共3张业务主表+1张三向关联中间表:

  • cities(城市表),表结构:
    City table
  • movies(电影表),表结构:
    电影表结构
  • theatres(影院表),表结构:
    影院表结构
  • 中间表city_movie_theatre用于关联三张主表,表结构:
    中间表结构

需求为查询同时匹配指定city_id和movie_id的影院记录,当前代码未加入城市维度筛选,无法返回正确结果。

当前已有代码

控制器代码:

class MovieController extends Controller
{
    public function test(){
        $city_id=1;
        $movie_id=1;
        $th=Movie::where('id',$movie_id)->first();
        dd($th->theatre);
    }
}

Movie模型:

class Movie extends Model
{
    use HasFactory;
    public function theatre(){
        return $this->belongsToMany(Theatre::class,'city_movie_theatre');
    }
    public function city(){
        return $this->belongsToMany(City::class,'city_movie_theatre');
    }
}

Theatre模型:

class Theatre extends Model
{
    use HasFactory;
    public function city(){
        return $this->belongsToMany(City::class,'city_movie_theatre');
    }
    public function movie(){
        return $this->belongsToMany(Movie::class,'city_movie_theatre','theatre_id','movie_id');
    }
}

中间表模型:

use Illuminate\Database\Eloquent\Relations\Pivot;
class City_Movie_Theatre extends Pivot
{
    use HasFactory;
    protected $table='city_movie_theatre';
    
}

实现方案

核心问题说明

原有代码不生效的核心原因:

  1. 直接通过动态属性$th->theatre取关联数据时,ORM会先执行全量关联查询,无法再追加中间表筛选条件
  2. 多对多关联未声明中间表额外字段,无法直接对city_id做条件过滤

最快可用修改

不需要调整模型,直接修改控制器代码,通过关联查询构造器的wherePivot方法筛选中间表字段即可:

class MovieController extends Controller
{
    public function test(){
        $city_id = 1;
        $movie_id = 1;
        // 先拿到电影模型实例,再通过关联构造器加中间表条件,最后查结果集
        $theatres = Movie::find($movie_id)
            ->theatre() // 调用关联方法拿到查询构造器,不是直接取属性
            ->wherePivot('city_id', $city_id) // 筛选中间表的city_id
            ->get();
        dd($theatres);
    }
}

推荐的模型规范优化

建议把关联方法改为复数形式(一个电影对应多个影院/城市,语义更清晰),同时显式声明关联外键和中间表字段,避免ORM自动推断出错:

// Movie 模型
class Movie extends Model
{
    use HasFactory;
    public function theatres(){
        return $this->belongsToMany(
            Theatre::class,
            'city_movie_theatre',
            'movie_id',
            'theatre_id'
        )->withPivot('city_id'); // 声明中间表携带的额外字段
    }

    public function cities(){
        return $this->belongsToMany(
            City::class,
            'city_movie_theatre',
            'movie_id',
            'city_id'
        )->withPivot('theatre_id');
    }
}
// Theatre 模型
class Theatre extends Model
{
    use HasFactory;
    public function cities(){
        return $this->belongsToMany(
            City::class,
            'city_movie_theatre',
            'theatre_id',
            'city_id'
        )->withPivot('movie_id');
    }

    public function movies(){
        return $this->belongsToMany(
            Movie::class,
            'city_movie_theatre',
            'theatre_id',
            'movie_id'
        )->withPivot('city_id');
    }
}

优化后查询写法和上面一致,后续需要获取中间表字段时可以直接通过$model->pivot->字段名取值。

可选查询方式

如果需要从影院入口筛选,也可以用whereHas做关联存在性查询,最终生成的SQL和上面写法等价:

$theatres = Theatre::whereHas('movies', function($query) use ($movie_id, $city_id){
    $query->where('movies.id', $movie_id)
          ->where('city_movie_theatre.city_id', $city_id);
})->get();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 17:30:50