yii2 ActiveRecord多表关联以及多表关联搜索的实现

一个老生常谈的问题。最近通过群里的反馈,觉得很多人还是没有去理解这个问题。今天把这个问题讲明白了,看看yii2 ActiveRecord是怎么个多表关联以及如何去优化这个关联。

场景需求:

假设我们有一张用户表user和一张用户渠道表auth,两张数据表通过user.id和auth.uid进行一对一关联。现需要在user列表展示auth表的来源渠道source,且该渠道可搜索。

首先我们先通过gii生成user和auth系列相关的model和操作。此处不做详细说明,有关gii的操作可参考xxx

我看继续看重要的几个操作步骤:

1、找到user表对应的AR模型类 app\models\User.php,在该类文件中进行关联auth表

/**
* 关联auth表
*/
public function getAuth()
{
// hasOne要求返回两个参数 第一个参数是关联表的类名 第二个参数是两张表的关联关系
// 这里uid是auth表关联id, 关联user表的uid id是当前模型的主键id
return $this->hasOne(common\models\Auth::className(), ['uid' => 'id']);
}

设置好了之后,并不代表两张数据表自动进行关联了!我们访问user列表页(该列表页采用gii生成,目前我们没操作过),通过debug查看Database Queries不难发现,实际中的query并没有进行关联auth表

2、在gridview中添加关联表的来源渠道字段source

<?= GridView::widget([
// other codes
'columns' => [
// other columns
'auth.source',
]
]); ?>

有同学感觉疑问了,上面不是说了没进行关联吗,这个怎么可以直接使用auth.source?

先别急,此时我们打开debug看看实际的query。

我们会发现有很多类似 select * from auth where uid = xxx;之类的操作,如果你的分页默认20条数据时,会有20个类似的query。

我们先搞明白发生了什么?

实际上这属于php的基础知识了。读取和写入对象的一个不存在的成员变量时, get() set() 魔术函数会被自动调用。yii也是利用了这一点对其进行了实现!

该操作跟大部分人在gridview中封装方法获取关联表数据几乎一致,但是!20条sql的查询明显增加了众多的开销。如果这里是left join操作多好!

3、优化sql

我们需要优化的是:

20条sql变1条sql

只获取关联表需要的字段

有同学要嚷嚷了,这里是yii自带的操作,怎么优化?我们回到数据源的获取上,发现user列表的数据是通过userSearch model的search方法提供的。

也就是说我们的数据查询实际上就没有去进行关联表查询!既然如此,我们就在UserSearch加上关联查询

$query = User::find();
$query->joinWith(['auth']);
$query->select("user.*, auth.source");

我们再来刷新下user列表页,然后通过debug分析发现有两条sql引起了我们的注意

SELECT `user`.*, `auth`.`source` FROM `user` LEFT JOIN `auth` ON `user`.`id` = `auth`.`uid` LIMIT 20
SELECT * FROM `auth` WHERE `user_id` IN (20个uid);

也就是说我么已经达到了优化sql的目的,通过debug分析发现,DB的查询时间少了很多。

4、关联表字段增加查询

gridview中的搜索模型也是通过searchModel实现的,该模型通过rules控制着哪个字段可搜索,哪个字段不可搜索。

我们现在需要增加关联表的source可搜索,因此我们在searchModel中定义一个属性source且添加到rules中

public $source;
public function rules()
{
return [
// other rules
['source', 'safe'],
];
}

接着我们把gridview中的auth.source修改一下

// 'auth.source',
[
'attribute' => 'source',
'value' => 'auth.source',
'label' => '渠道来源',
],

到这里我们界面上是ok的,要实现程序上的搜索还差一步,我们在数据源获取的地方加上新增的source条件即可

$query->andFilterWhere([
// other params
'auth.source' => $this->source,
]); 实例如下:


手册中yii2的关联模型:

查询关联的数据

使用 AR 方法也可以查询数据表的关联数据(如,选出表A的数据可以拉出表B的关联数据)。 有了 AR, 返回的关联数据连接就像连接关联主表的 AR 对象的属性一样。

建立关联关系后,通过 $customer->orders 可以获取 一个 Order 对象的数组,该数组代表当前客户对象的订单集。

定义关联关系使用一个可以返回 yii\db\ActiveQuery 对象的 getter 方法, yii\db\ActiveQuery对象有关联上下文的相关信息,因此可以只查询关联数据。

例如:

class Customer extends \yii\db\ActiveRecord
{
public function getOrders()
{
// 客户和订单通过 Order.customer_id -> id 关联建立一对多关系
return $this->hasMany(Order::className(), ['customer_id' => 'id']);
}
} class Order extends \yii\db\ActiveRecord
{
// 订单和客户通过 Customer.id -> customer_id 关联建立一对一关系
public function getCustomer()
{
return $this->hasOne(Customer::className(), ['id' => 'customer_id']);
}
}
 

yii2中关联查询的更多相关文章

  1. THINKPHP 中关联查询(多表查询)

    THINKPHP 中关联查询(多表查询)可以使用 table() 方法或和join方法,请看示例: 1.Table方法:定义要操作的数据表名称,可以动态改变当前操作的数据表名称,需要写数据表的全名,包 ...

  2. Mongoose中关联查询populate的使用

    MongoDB中没有join的特性,因此无法使用join进行表的连接和关联查询,在Mongoose中封装了populate方法,在定义一个 Schema 的时候可以指定了其中的字段(属性)是另一个Sc ...

  3. SSM-MyBatis-15:Mybatis中关联查询(多表操作)

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 先简单提及一下关联查询的分类 1.一对多 1.1单条SQL操作的 1.2多条SQL操作的 2.多对一 2.1单 ...

  4. wcf+linq to sql中关联查询返回数据问题

    前段时间准备采用wcf+nh框架开发sl程序,发现采用nh开发不适合我的中型.并且快速开发项目,所以综合考量了下,决定采用wcf+linq to sql . 但是此模式也有缺点,也是linq to s ...

  5. python&django 实现页面中关联查询小功能(中级篇)

    目的 组合搜索实现如下图功能 知识点 1.使用自定义标签模板(templatetags) 实现 models.py 和 views.py和初级篇一样 重点如下:在app01目录下创建templatet ...

  6. python&django 实现页面中关联查询小功能(基础篇)

    效果 实现效果图如下,根据过滤条件查询相关信息. 知识点 1.配置URL,在路由中使用正则表达式 2.过滤查询 代码 setting.py from django.contrib import adm ...

  7. tp5 模型中 关联查询(省去了foreach写法)

    1.控制器中 $list = Userlawsbook::where($where)->with('lawsbook')->paginate(7);  // 此处查出来为数组对象 dump ...

  8. YII2中where查询中多个or查询

    使用多个or的复杂查询: AND ((`name`='张三') OR (`name`='李四') OR (`name`='王五')) // AND ((`name`='张三') OR (`name`= ...

  9. Yii2中多表关联查询(join、joinwith)

    我们用实例来说明这一部分 表结构 现在有客户表.订单表.图书表.作者表, 客户表Customer   (id  customer_name) 订单表Order      (id  order_name ...

随机推荐

  1. Egret动态设置按钮的图片

    参考: 动态设置Button按钮的状态图片 按钮有3个状态,up down disabled.这里区别于source,source.down,source.disabled,而是每个状态单独一个ima ...

  2. 【BZOJ1187】[HNOI2007]神奇游乐园 插头DP

    [BZOJ1187][HNOI2007]神奇游乐园 Description 经历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细 ...

  3. springMVC 几种页面跳转方式

    今天主要写一下响应界面跳转的几种方式 1.在注解的方式中 1.1通过HttpServletResponse的API直接输出(不需要配置渲染器) controller类的主要代码 @Controller ...

  4. vue--提取公共方法

    在做一个项目的时候,一些组件内公用的方法可以单独提取出来做复用: 参考:https://www.jb51.net/article/115662.htm 简单示例: 代码: const config = ...

  5. Spark2 DataSet 创建新行之flatMap

    val dfList = List(("Hadoop", "Java,SQL,Hive,HBase,MySQL"), ("Spark", & ...

  6. 纯CSS绘制的三角形箭头图案【原创】

    参考:http://www.webhek.com/css-triangles/ 使用上下左右的三角形箭头标志,直接用css即可完成,直接附上代码. css: div#up { width: 0px; ...

  7. 电话、地址、Email等常用正则表达式

    正则表达式用于字符串处理.表单验证等场合,实用高效.现将一些常用的表达式收集于此,以备不时之需. 匹配中文字符的正则表达式: [\u4e00-\u9fa5]评注:匹配中文还真是个头疼的事,有了这个表达 ...

  8. NGINX域名跳转案列

    1.不同域名不同路径跳转 nginx实现a.com/teacher域名跳转到b.com/student 若想实现上面题目的跳转,目前鄙人知道两种方式: 1.return 2.proxy_pass 具体 ...

  9. Python重要基础点

    这里记录一些实际编写代码时遇到的常用/重要的内容,有前辈的,也有自己整理加进来的. 以点的形式记录,之后遇到的内容会慢慢补充进来 1. 斜杠 / :斜字第一笔, 转义用反斜杠 \ : 转的最后一笔 2 ...

  10. PPTP客户端无法拨号778故障解决

    Win7客户端无法拨号提示778 CentOS服务器端 日志/var/log/messages提示一下错误信息 GRE: read(fd=6,buffer=611860,len=8196) from ...