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的功能。如有其余方法,請評論。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM