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

2.withJoin的特性

2.1 第一个特性

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

的博文中,阐述了利用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查询概念,请搜索网络)。即如果将博文

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

 中的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的功能。如有其余方法,请评论。

 

 

posted @ 2021-06-03 23:07  秦皇汉武  阅读(7173)  评论(3编辑  收藏  举报