假设主表是班级Class,副表是学生Student。 建立一对多关系后,可以轻松得到各班级包含的学生。
按条件筛选,如果是基于主表Class的,比如只看英语班的学生,查询可以是Class::with(['student'])->where("班级类型","英语")->get();
但是如果是基于副表Student的筛选条件,比如有几个班全是女学生,现在只查询男学生所在班级和学生信息,这么写:
Class::with(['student'=>function($query){
$query->where("学生性别","男");
}])->get();
则查询的结果会先执行select * from Class; 还是会返回有女学生的班级(只是没有Student学生数据),然后在符合副表筛选条件的Class下充填Student数据。
而我希望返回的结果只是男学生所在的Class和Student信息
加上whereHas后:
Class::whereHas('student',function($query){
$query->where("学生性别","男");
})->with(['student'=>function($query){
$query->where("学生性别","男");
}])->get();
如果这么写,倒是可以只返回男学生所在的Class和Student信息
可是这样是不是比较麻烦了,需要把副表的筛选条件在whereHas和with里都要写一遍,有没有更加优雅的Orm写法呢? 若是使用DB的join则简单许多了吧?
whereHas
是一个前置条件,用来确保,在查询出来的 Class 一定是符合 where 的条件的,而with
方法才是最终查询 Student 时使用到的,所以存在在这个问题。其次,更加建议使用 join 来处理类似的问题,因为
whereHas
会使用子查询来处理,存在一些性能问题。当然,你也可以坚持使用 whereHas + with 的方式,你把你那一个查询的匿名函数声明成变量就好了。