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

Laravel多对多关系查询:实现班级与科目关联数据分组展示

解决Laravel多对多关系下按班级分组展示科目代码的问题

问题分析

当前通过join查询返回的是班级-科目的关联明细数据,同一个班级会对应多条记录,导致前端循环时重复渲染班级行,无法实现“一行一个班级+对应所有科目代码”的展示效果。

解决方案

方案1:利用Eloquent关联预加载(推荐)

首先确保你的Classe模型(注意Class是PHP关键字,建议重命名为Classe)已定义与Subject的多对多关联:

// app/Models/Classe.php
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Classe extends Model
{
    protected $table = 'classes';

    // 定义与科目多对多关联
    public function subjects()
    {
        // 参数依次:关联模型、中间表名、当前模型外键、关联模型外键
        return $this->belongsToMany(Subject::class, 'classe_subjects', 'class', 'subject');
    }
}

修改ClassController的index方法,预加载科目关联,避免N+1查询问题:

public function index()
{
    // 预加载每个班级对应的所有科目
    $classes = \App\Models\Classe::with('subjects')->get();
    return view('classes.index', compact('classes'));
}

更新前端classes/index.blade.php模板,循环每个班级并遍历其科目:

<table class="table table-striped table-responsive">
  <thead class="table-bordered">
    <tr>
       <th>班级名称</th>
       <th>科目</th>
       <th>学生人数</th>
       <th>操作</th>
     </tr>
  </thead>
  <tbody>
  @foreach($classes as $class)
    <tr>
       <td>{{ $class->name }}</td>
       <td>
           @foreach($class->subjects as $subject)
               <span class="border border-secondary border-radius bg-secondary-light p-1">{{ $subject->code }}</span>
           @endforeach
       </td>
       <td>
           <span class="border border-secondary border-radius bg-secondary-light p-1">{{ $class->student_count ?? 50 }}</span>
       </td>
       <td>
            <a href="{{ route('classes.show', $class->id) }}"><i class="bi bi-eye text-secondary"></i></a>
            <a href="{{ route('classes.edit', $class->id) }}"><i class="bi bi-pencil-square text-primary"></i></a>
            <a href="#" onclick="event.preventDefault(); document.getElementById('delete-form-{{ $class->id }}').submit();"><i class="bi bi-trash text-danger"></i></a>
            <form id="delete-form-{{ $class->id }}" action="{{ route('classes.destroy', $class->id) }}" method="POST" style="display: none;">
                @csrf
                @method('DELETE')
            </form>
       </td>
    </tr>
  @endforeach
  </tbody>
</table>

方案2:使用SQL分组聚合(GROUP_CONCAT)

如果希望直接在查询中拼接好科目代码,可修改Controller的查询逻辑:

public function index()
{
    $classes = \App\Models\Classe::select('classes.*')
        ->join('classe_subjects', 'classes.id', '=', 'classe_subjects.class')
        ->join('subjects', 'classe_subjects.subject', '=', 'subjects.id')
        // 用GROUP_CONCAT拼接科目代码,逗号分隔
        ->selectRaw('classes.*, GROUP_CONCAT(subjects.code SEPARATOR ", ") as subject_codes')
        // 按班级ID分组
        ->groupBy('classes.id')
        ->get();
    return view('classes.index', compact('classes'));
}

对应前端模板简化为:

<td>{{ $class->subject_codes }}</td>

效果说明

两种方案都能实现:每行展示一个班级名称,对应列显示该班级的所有科目代码(方案1为标签形式,方案2为逗号分隔的文本形式),与你期望的展示效果一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 12:15:57