THINKPHP_(4)_TP模型中with、withJoin和多层关联的深入分析
2.withJoin的特性
2.1 第一个特性
的博文中,阐述了利用withJoin进行关联查询的情况。这里补充一个命名特性(经过调试确认)
即关系命名的,必须与模型名保持一致,否则withJoin无法使用。(当这个不满足时,with仍可使用。大家可以调试确认)
即关系名中的School和Xueqi等必须与关联模型一致,才能使用withJoin。
2.12第二个特性
withJoin的关联查询,只支持单层关联,不支持多层。
比如:
->withJoin( [ 'canxunDanweiSchool' => function($query){ $query ->withJoin(['dwJibie','xiaojieShangJiDanwei']) ; }, 'canxunpeiyangjihuaXueqi' => function($query) use($src){ $query ->withJoin(['glCategory','pyCategory','xnCategory']) ; }, ]
)
这里可能想表达,"多层关联,即先关联到School表,再从school表中多层关联到Category表。类似的,先关联到Xueqi,再关联到Category表。“
注意,此时,使用如下代码进行单层关联查询,是可行的。
->when(count($src['canxunPeiyangjihua_pyCategory']) > 0, function($query) use($src){ $query->where('canxunpeiyangjihuaXueqi.peiyang_category_id', 'in', $src['canxunPeiyangjihua_pyCategory']);
})
但是,无法返回多层关联数据,即withJoin无法返回二层关联的glCategory、dwJibie等关系中的任何数据。
返回多层关联数据,只能用with,而不能用withJoin。详见博文:
TP6中实现多层关联,第一个表关联第二个表查询出的数据,再关联第三个表
3.with的特性
虽然前述博文中,with能够查询出多层的数据,但是with不支持类似于withJoin的inner Join查询(关于inner Join查询概念,请搜索网络)。即如果将博文
中的withJoin换成with,是无法实现withJoin功能的。
即使在with的代码中,添加where,那么只能实现的是关联表中的数据过滤,而不涉及本表,即不能实现join的功能。比如,如下代码:
->with( [ 'canxunDanweiSchool' => function($query){ $query ->with(['dwJibie','xiaojieShangJiDanwei']) // ->field('id, title, jiancheng')//如果通过field设置输出字段,会限制关联查询dwJibie // ->withField('dwJibie') ; }, 'canxunpeiyangjihuaXueqi' => function($query) use($src){ $query ->with(['glCategory','pyCategory','xnCategory']) // ->when(count($src['canxunPeiyangjihua_pyCategory']) > 0, function($query) use($src){ // $query->where('peiyang_category_id', 'in', $src['canxunPeiyangjihua_pyCategory']); //// ->field('id, title, jiancheng')//如果通过field设置输出字段,会限制关联查询dwJibie //// ->withField('dwJibie') // }) ; }, ] )
其中在关系中添加的where查询,只会使得关联表中的数据进行过滤,不会对本表查询的数据进行where过滤。
比如:表a的某行数据data1,在表b中关联的某行数据,不满足where条件,那么返回的数据是,表a中的data1仍然被返回,只是表b中对应的关联数据被筛选掉。这达不到innerJoin功能。
即无法通过with中的where语句来对本表返回的数据进行筛选。而join是要实现这种功能的。
4.实现多层关联数据查询,并在关联表中实现where功能,inner join到本表。
代码如下:
// $xxx=Db::query('select id from cj_canxundanwei'); // 整理参数 $src = [ 'school_id' => array() ,'xueqi_id' => array() ,'canxunPeiyangjihua_pyCategory'=> array() //搜索培养大类 ]; $src = array_cover($srcfrom, $src); $src['school_id'] = strToArray($src['school_id']); $src['xueqi_id'] = strToArray($src['xueqi_id']); $src['canxunPeiyangjihua_pyCategory'] = strToArray($src['canxunPeiyangjihua_pyCategory']); // 查询数据 $data = $this ->with( [ 'canxunDanweiSchool' => function($query){ $query ->with(['dwJibie','xiaojieShangJiDanwei']) // ->field('id, title, jiancheng')//如果通过field设置输出字段,会限制关联查询dwJibie ; }, 'canxunpeiyangjihuaXueqi' => function($query) use($src){ $query ->with(['glCategory','pyCategory','xnCategory']) ; }, ] ) ->when(count($src['school_id']) > 0, function($query) use($src){ $query->where('school_id', 'in', $src['school_id']); }) ->when(count($src['xueqi_id']) > 0, function($query) use($src){ $query->where('xueqi_id', 'in', $src['xueqi_id']); }) ->when(count($src['canxunPeiyangjihua_pyCategory']) > 0, function($query) use($src) { /* * 使用原生SQL语句 */ // Db::query('select id from cj_canxundanwei'); // $a='('; // foreach($src['canxunPeiyangjihua_pyCategory'] as $value){ // $a=$a.(String)$value.','; // } // $a=substr($a,0,strlen($a)-1); // $a=$a.')'; // $xxx=Db::query('select c.id from cj_canxundanwei c INNER JOIN cj_xueqi x ON c.xueqi_id = x.id where x.peiyang_category_id in '.$a); // $ddd=array(); // foreach($xxx as $value){ // array_push($ddd,(String)$value['id']); // } // $query->where('id','in',$ddd); /* * 使用原生SQL语句 */ $sch = new CX; $eee=$sch->withJoin(['canxunpeiyangjihuaXueqi'=>function($query){ $query->field('peiyang_category_id'); },])->where("canxunpeiyangjihuaXueqi.peiyang_category_id",'in', $src['canxunPeiyangjihua_pyCategory']) ->field('Canxundanwei.id')->select(); $query->where('id','in',$eee); }) ->select();
即,只能使用原生sql语句。其中被注释"使用原生sql语句"注释掉的代码中为正确内容。而如下代码中执行的内容,返回的数据是thinkPHP的collection数据
$sch = new CX; $eee=$sch->withJoin(['canxunpeiyangjihuaXueqi'=>function($query){ $query->field('peiyang_category_id'); },])->where("canxunpeiyangjihuaXueqi.peiyang_category_id",'in', $src['canxunPeiyangjihua_pyCategory']) ->field('Canxundanwei.id')->select();
所以,
$query->where('id','in',$eee);
执行会失败。
注意,db引用的是think\facade\Db类。
即,只能使用原生sql语句,实现多层关联数据查询的同时,同时再实现inner Join的功能。如有其余方法,请评论。