Laravel 5中基于多层关联模型实现count()统计的技术问询
多层级关联下的Count统计解决方案(基于Laravel模型关联)
首先咱们先把模型之间的关联关系捋清楚——这是做多层统计的基础,先解决你对courses关联rosters的疑惑,再一步步实现统计需求。
第一步:确认并定义正确的模型关联
根据你描述的关联逻辑,我先给出合理的Laravel模型关联定义(从控制器、@foreach的用法来看,你大概率用的是Laravel框架):
1. School 模型
class School extends Model { // 一个学校对应多个课程 public function courses() { return $this->hasMany(Course::class); } // 一个学校对应多个学生 public function students() { return $this->hasMany(Student::class); } }
2. Course 模型
关于你疑惑的courses关联rosters:如果逻辑是一个课程对应唯一的选课花名册,那用hasOne是合理的(假设rosters表有course_id外键):
class Course extends Model { public function school() { return $this->belongsTo(School::class); } // 一个课程对应一个花名册 public function roster() { return $this->hasOne(Roster::class); } }
3. Roster 模型
class Roster extends Model { // 花名册属于某个课程 public function course() { return $this->belongsTo(Course::class); } // 一个花名册对应多个学生(假设`students`表有`roster_id`外键) public function students() { return $this->hasMany(Student::class); } }
4. Student 模型
class Student extends Model { public function school() { return $this->belongsTo(School::class); } public function roster() { return $this->belongsTo(Roster::class); } }
如果你的courses和rosters关联逻辑反过来(比如一个花名册对应多个课程),只需要把Course的roster()改成belongsTo,Roster添加hasMany(Course::class)即可,后面的统计逻辑也会对应调整。
第二步:实现多层级关联的Count统计
接下来分两种常见场景给出解决方案,同时避免N+1查询问题:
场景1:统计每个课程对应的花名册学生数
在查询学校时,用**嵌套withCount**预加载统计数据,这样一次查询就能拿到所有需要的信息:
// 控制器代码 $school = School::with([ 'courses' => function ($query) { // 统计每个课程的花名册下的学生数量 $query->withCount('roster.students'); } ])->find($yourSchoolId);
然后在视图的@foreach里直接调用统计结果:
@foreach($school->courses as $course) <p>课程:{{ $course->name }},选课人数:{{ $course->roster_students_count }}</p> @endforeach
这里roster_students_count是Laravel自动生成的统计字段名,规则是关联名_关联名_count。
场景2:统计整个学校所有课程的花名册学生总数
如果需要统计学校下所有课程的选课总人数,有两种方式:
方式一:用withSum嵌套统计
use Illuminate\Support\Facades\DB; $school = School::withSum( ['courses.roster.students' => function ($query) { $query->select(DB::raw('count(id)')); }], 'total_students' )->find($yourSchoolId); // 直接访问总人数 $totalStudents = $school->total_students;
方式二:在School模型里定义自定义统计方法
// School模型添加方法 use Illuminate\Support\Facades\DB; public function getTotalRosterStudentsAttribute() { return $this->courses() ->join('rosters', 'courses.id', '=', 'rosters.course_id') ->join('students', 'rosters.id', '=', 'students.roster_id') ->distinct() // 避免重复统计同一学生(如果学生可能在多个花名册) ->count('students.id'); }
然后在控制器或视图里直接调用:
// 控制器 $total = $school->total_roster_students; // 视图 <p>学校总选课人数:{{ $school->total_roster_students }}</p>
关键提醒
- 一定要用预加载(
with/withCount),不然在@foreach里循环调用关联会触发大量重复查询,拖慢性能; - 如果你的关联逻辑和我假设的有出入(比如
rosters和students是多对多),只需要调整模型的关联方法(把hasMany改成belongsToMany),统计逻辑基本可以复用。
内容的提问来源于stack exchange,提问作者maximus1127
相关产品推荐
相关产品推荐

