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. 908. Smallest Range I

    Given an array A of integers, for each integer A[i] we may choose any x with -K <= x <= K, and ...

  2. php 简易日志函数应用 debug_backtrace()

    1 public static function writeILogs($datas) 2 { 3 $bt = debug_backtrace(); 4 $caller = array_shift($ ...

  3. mysql 密码忘记解决办法

    bin>net stop mysql bin>mysqld --skip-grant-tables bin>mysql mysql>use mysql mysql>upd ...

  4. Windows核心编程 第四章 进程(下)

    4.3 终止进程的运行 若要终止进程的运行,可以使用下面四种方法: • 主线程的进入点函数返回(最好使用这个方法) . • 进程中的一个线程调用E x i t P r o c e s s函数(应该避免 ...

  5. ajax提交session超时跳转页面使用全局的方法来处理

    来自:http://www.jb51.net/article/43770.htm 如果是ajax提交,超时时从服务器发出的跳转命令就不会起作用,所以如果是session超时,而且是在ajax请求,就在 ...

  6. Ubuntu Linux 学习篇 配置DHCP服务器

    isc-dhcp-server 动态主机配置协议是一个局域网的网络协议.指的是由服务器控制一段IP地址范围,客户机登录服务器时就可以自动获得服务器分配的IP地址和子网掩码.首先, DHCP服务器必须是 ...

  7. Android 面试必备 - 系统、App、Activity 启动过程“一锅端”

    Android 系统启动过程 从系统层看: linux 系统层 Android系统服务层 Zygote 从开机启动到Home Launcher: 启动bootloader (小程序:初始化硬件) 加载 ...

  8. 【实用小技巧】spring与springmvc自动扫描包重复的问题解决

    spring对应配置文件为: <!-- 配置自动扫描的包,此时要排除Controller --> <context:component-scan base-package=" ...

  9. Kafka源码分析系列-目录(收藏不迷路)

    持续更新中,敬请关注! 目录 <Kafka源码分析>系列文章计划按"数据传递"的顺序写作,即:先分析生产者,其次分析Server端的数据处理,然后分析消费者,最后再补充 ...

  10. C#·对于BOM头之完全解决方案

    阅文时长 | 0.46分钟 字数统计 | 798.4字符 主要内容 | 1.引言&背景 2.使用C#写入带有/不带有BOM头的文件? 3.对于读取文件时,避免BOM头造成的异常. 4.声明与参 ...