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功能

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

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

  1. THINKPHP_(2)_TP模型的多表关联查询和多表字段的关键字搜索。

    问题: 上述内容中,标题和学年属于一个数据表.分类则属于另外一个数据表,并且是利用id关联后,另外一个数据表中的title字段. 需要设置关键字搜索,实现多表关联查询和多表字段的关键字搜索. 解决方法 ...

  2. THINKPHP_(8)_修改TP源码,支持基于多层关联的任一字段进行排序

    之前博文 前述博文THINKPHP_(1)_修改TP源码,支持对中文字符串按拼音进行排序,其解决的主要问题是,对于查询出的think\collection数据,按指定字段对数据进行排序,从而在页面上进 ...

  3. Entity Framework 6 Recipes 2nd Edition(10-5)译 -> 在存储模型中使用自定义函数

    10-5. 在存储模型中使用自定义函数 问题 想在模型中使用自定义函数,而不是存储过程. 解决方案 假设我们数据库里有成员(members)和他们已经发送的信息(messages) 关系数据表,如Fi ...

  4. Entity Framework 6 Recipes 2nd Edition(10-6)译 -> TPT继承模型中使用存储过程

    10-6. TPT继承模型中使用存储过程 问题 想在一个TPT继承模型中使用存储过程 解决方案 假设已有如Figure 10-6所示模型. 在模型里, Magazine(杂志) and DVD继承于基 ...

  5. Entity Framework 6 Recipes 2nd Edition(10-7)译 -> TPH继承模型中使用存储过程

    10-7. TPH继承模型中使用存储过程 问题 用一个存储过程来填充TPH继承模型的实体 解决方案 假设已有如Figure 10-7所示模型. 我们有两个派生实体: Instructor(教员)和St ...

  6. [Asp.net MVC]Asp.net MVC5系列——在模型中添加验证规则

    目录 概述 在模型中添加验证规则 自定义验证规则 伙伴类的使用 总结 系列文章 [Asp.net MVC]Asp.net MVC5系列——第一个项目 [Asp.net MVC]Asp.net MVC5 ...

  7. thinkphp在模型中自动完成session赋值

    相信用过thinkphp的用户都知道thinkphp的模型可以完成很多辅助功能,比 如自动验证.自动完成等,今天在开发中遇到自动完成中需要获取session值 然后自动赋值的功能,具体看代码:clas ...

  8. [Asp.net MVC]Asp.net MVC5系列——从控制器访问模型中的数据

    目录 概述 从控制器访问模型中的数据 强类型模型与@model关键字 总结 系列文章 [Asp.net MVC]Asp.net MVC5系列——第一个项目 [Asp.net MVC]Asp.net M ...

  9. django模型中的抽象类(abstract)

    首先介绍下django的模型有哪些属性:先看例子: Django 模型类的Meta是一个内部类,它用于定义一些Django模型类的行为特性.以下对此作一总结: abstract 这个属性是定义当前的模 ...

随机推荐

  1. Laravel5.6教程之——安装

    1.安装 方式1:全局安装 通过composer安装 laravel 安装器 composer global require "laravel/installer" 1 确保将 c ...

  2. hdu1466 递推

    题意:       给你n条直线,不会存在三线共点,输出所有的可能交点数.. 思路:       这个是个地推的题目,假设当前的线段i,他里面有r条是随意的,有(i - r)条是平行的,那么当前的交点 ...

  3. POJ2135 来回最短路(简单费用流)

    题意:       就是从1走到n然后再走回来,一条边只能走一次,要求路径最短. 思路:       比较水,可以直接一遍费用流,不解释了,具体的看看代码,敲这个题就是为了练 练手,好久不敲了,怕比赛 ...

  4. Windows核心编程 第十五章 在应用程序中使用虚拟内存

    第1 5章 在应用程序中使用虚拟内存 Wi n d o w s提供了3种进行内存管理的方法,它们是: • 虚拟内存,最适合用来管理大型对象或结构数组. • 内存映射文件,最适合用来管理大型数据流(通常 ...

  5. 机器视觉-EasyDL商品检测-标准版-Demo

    机器视觉-EasyDL商品检测-标准版 功能: EasyDL是百度大脑中的一个定制化训练和服务平台,EasyDL零售版是EasyDL针对零售场景推出的行业版,定制商品检测服务是EasyDL零售版的一项 ...

  6. HellowWorld详解

    1.随便新建一个文件夹,存放代码 2.在文件夹中新建一个Java文件 新建一个.txt文本文档-->将扩展名.txt修改为.java 注:如果创建的文本文档没有显示扩展名,则有如下方法: 方法一 ...

  7. ElasticSearch7.10.0入门学习

    ElasticSearch完成最关键的一个功能就是 大数据搜索 官网:https://www.elastic.co/cn/elasticsearch/ 简介 Elasticsearch 是一个分布式全 ...

  8. Redis中几种数据类型的基本操作指令

    Redis基本指令 单线程+多路IO复用技术 1. Key 指令 作用 keys * 查看当前库所有键 exists <key> 判断此键是否存在 type <key> 查看键 ...

  9. window下批量删除指定后缀文件

    例子: 批量删除当前路径下后缀为 .jpg和 .json del /a /f /s /q "*.jpg" "*.json" *为通配符/a /f 是强制删除所有 ...

  10. 视频格式mkv、mp4、avi、flv、mov、wmv、webm特点和区别

    mkv是一种多媒体封装格式,这个封装格式可把多种不同编码的影像及 16 条或以上不同格式的音频和语言不同的字幕封装到一个 Matroska Media 档内. 它也是其中一种开放原始码的多媒体封装格式 ...