THINKPHP_(4)_TP模型中with、withJoin和多层关联的深入分析

2.withJoin的特性

2.1 第一个特性

TP模型的多表关联查询和多表字段的关键字搜索

的博文中,阐述了利用withJoin进行关联查询的情况。这里补充一个命名特性(经过调试确认

即关系命名的,必须与模型名保持一致,否则withJoin无法使用。(当这个不满足时,with仍可使用。大家可以调试确认)

即关系名中的School和Xueqi等必须与关联模型一致,才能使用withJoin。

2.12第二个特性

withJoin的关联查询,只支持单层关联,不支持多层。

比如:

  1. ->withJoin(
  2. [
  3. ‘canxunDanweiSchool’ => function($query){
  4. $query
  5. ->withJoin([‘dwJibie’,‘xiaojieShangJiDanwei’])
  6. ;
  7. },
  8. ‘canxunpeiyangjihuaXueqi’ => function($query) use($src){
  9. $query
  10. ->withJoin([‘glCategory’,‘pyCategory’,‘xnCategory’])
  11.             ;
  12. },
  13. ]
    )

这里可能想表达,”多层关联,即先关联到School表,再从school表中多层关联到Category表。类似的,先关联到Xueqi,再关联到Category表。“

注意,此时,使用如下代码进行单层关联查询,是可行的。

  1. ->when(count($src[‘canxunPeiyangjihua_pyCategory’]) > 0, function($query) use($src){
  2. $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查询概念,请搜索网络)。即如果将博文

TP模型的多表关联查询和多表字段的关键字搜索

中的withJoin换成with,是无法实现withJoin功能的。

即使在with的代码中,添加where,那么只能实现的是关联表中的数据过滤,而不涉及本表,即不能实现join的功能。比如,如下代码:

  1. ->with(
  2. [
  3. ‘canxunDanweiSchool’ => function($query){
  4. $query
  5. ->with([‘dwJibie’,‘xiaojieShangJiDanwei’])
  6. // ->field(‘id, title, jiancheng’)//如果通过field设置输出字段,会限制关联查询dwJibie
  7. // ->withField(‘dwJibie’)
  8. ;
  9. },
  10. ‘canxunpeiyangjihuaXueqi’ => function($query) use($src){
  11. $query
  12. ->with([‘glCategory’,‘pyCategory’,‘xnCategory’])
  13. // ->when(count($src[‘canxunPeiyangjihua_pyCategory’]) > 0, function($query) use($src){
  14. // $query->where(‘peiyang_category_id’, ‘in’, $src[‘canxunPeiyangjihua_pyCategory’]);
  15. //// ->field(‘id, title, jiancheng’)//如果通过field设置输出字段,会限制关联查询dwJibie
  16. //// ->withField(‘dwJibie’)
  17. // })
  18. ;
  19. },
  20. ]
  21. )

其中在关系中添加的where查询,只会使得关联表中的数据进行过滤,不会对本表查询的数据进行where过滤。

比如:表a的某行数据data1,在表b中关联的某行数据,不满足where条件,那么返回的数据是,表a中的data1仍然被返回,只是表b中对应的关联数据被筛选掉。这达不到innerJoin功能

4.实现多层关联数据查询,并在关联表中实现where功能,inner join到本表。

代码如下:

  1. // $xxx=Db::query(‘select id from cj_canxundanwei’);
  2. // 整理参数
  3. $src = [
  4. ‘school_id’ => array()
  5. ,‘xueqi_id’ => array()
  6. ,‘canxunPeiyangjihua_pyCategory’=> array() //搜索培养大类
  7. ];
  8. $src = array_cover($srcfrom, $src);
  9. $src[‘school_id’] = strToArray($src[‘school_id’]);
  10. $src[‘xueqi_id’] = strToArray($src[‘xueqi_id’]);
  11. $src[‘canxunPeiyangjihua_pyCategory’] = strToArray($src[‘canxunPeiyangjihua_pyCategory’]);
  12. // 查询数据
  13. $data = $this
  14. ->with(
  15. [
  16. ‘canxunDanweiSchool’ => function($query){
  17. $query
  18. ->with([‘dwJibie’,‘xiaojieShangJiDanwei’])
  19. // ->field(‘id, title, jiancheng’)//如果通过field设置输出字段,会限制关联查询dwJibie
  20. ;
  21. },
  22. ‘canxunpeiyangjihuaXueqi’ => function($query) use($src){
  23. $query
  24. ->with([‘glCategory’,‘pyCategory’,‘xnCategory’])
  25. ;
  26. },
  27. ]
  28. )
  29. ->when(count($src[‘school_id’]) > 0, function($query) use($src){
  30. $query->where(‘school_id’, ‘in’, $src[‘school_id’]);
  31. })
  32. ->when(count($src[‘xueqi_id’]) > 0, function($query) use($src){
  33. $query->where(‘xueqi_id’, ‘in’, $src[‘xueqi_id’]);
  34. })
  35. ->when(count($src[‘canxunPeiyangjihua_pyCategory’]) > 0, function($query) use($src) {
  36. /*
  37. * 使用原生SQL语句
  38. */
  39. // Db::query(‘select id from cj_canxundanwei’);
  40. // $a='(‘;
  41. // foreach($src[‘canxunPeiyangjihua_pyCategory’] as $value){
  42. // $a=$a.(String)$value.’,’;
  43. // }
  44. // $a=substr($a,0,strlen($a)-1);
  45. // $a=$a.’)’;
  46. // $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);
  47. // $ddd=array();
  48. // foreach($xxx as $value){
  49. // array_push($ddd,(String)$value[‘id’]);
  50. // }
  51. // $query->where(‘id’,’in’,$ddd);
  52. /*
  53. * 使用原生SQL语句
  54. */
  55. $sch = new CX;
  56. $eee=$sch->withJoin([‘canxunpeiyangjihuaXueqi’=>function($query){
  57. $query->field(‘peiyang_category_id’);
  58. },])->where(“canxunpeiyangjihuaXueqi.peiyang_category_id”,‘in’, $src[‘canxunPeiyangjihua_pyCategory’])
  59. ->field(‘Canxundanwei.id’)->select();
  60. $query->where(‘id’,‘in’,$eee);
  61. })
  62. ->select();

即,只能使用原生sql语句。其中被注释”使用原生sql语句”注释掉的代码中为正确内容。而如下代码中执行的内容,返回的数据是thinkPHP的collection数据

  1. $sch = new CX;
  2. $eee=$sch->withJoin([‘canxunpeiyangjihuaXueqi’=>function($query){
  3. $query->field(‘peiyang_category_id’);
  4. },])->where(“canxunpeiyangjihuaXueqi.peiyang_category_id”,‘in’, $src[‘canxunPeiyangjihua_pyCategory’])
  5. ->field(‘Canxundanwei.id’)->select();

所以,

  1. $query->where(‘id’,‘in’,$eee);

执行会失败。

注意,db引用的是think\facade\Db类。

即,只能使用原生sql语句,实现多层关联数据查询的同时,同时再实现inner Join的功能。如有其余方法,请评论。


发表评论

电子邮件地址不会被公开。 必填项已用*标注