Yii2.0表关联查询实例分析


Posted in PHP onJuly 18, 2016

本文实例讲述了Yii2.0表关联查询的方法。分享给大家供大家参考,具体如下:

你可以使用 ActiveRecord 来进行关联查询(比如,从A表读取数据时把关联的B表数据也一起读出来), 在Active Record中,获取关联数据可以像访问主表ActiveRecord对象的属性(property)一样简单。

比如,通过合适的关系声明,你可以使用 $customer->orders 来获取一个 Order 对象数组,代表该客户下的订单。

要声明一个关系(relation),定义一个getter方法,该方法返回一个 yii\db\ActiveQuery 对象,拥有关联上下文信息,这样将只查询符合条件的相关数据。比如:

class Customer extends \yii\db\ActiveRecord
{
 public function getOrders()
 {
  // Customer has_many Order via Order.customer_id -> id
  return $this->hasMany(Order::className(), ['customer_id' => 'id']);
 }
}
class Order extends \yii\db\ActiveRecord
{
 // Order has_one Customer via Customer.id -> customer_id
 public function getCustomer()
 {
  return $this->hasOne(Customer::className(), ['id' => 'customer_id']);
 }
}

上述代码中的 yii\db\ActiveRecord::hasMany() 和 yii\db\ActiveRecord::hasOne() 是用来建模关系型数据库中的 一对多 以及 一对一 关联关系。比如,一个客户customer有多个订单orders,而一个订单拥有或归属于一个用户。两个方法均接收两个参数并返回一个 yii\db\ActiveQuery 对象:

$class: 关联模型的类名称。

$link: 两张表之间的列关联。这得是一个数组。数组元素的键是 $class 所对应表的列名称,而数组元素的值是当前声明类的列名称。依据表外键关联来定义这些关系是一个好的编程实践。

完成上述声明后,就可以通过定义相应的getter方法来像访问对象属性一样获取关联数据:

// get the orders of a customer
$customer = Customer::findOne(1);
$orders = $customer->orders; // $orders is an array of Order objects

上述代码在幕后实际执行了如下两个SQL查询,分别对应于上述两行代码:

SELECT * FROM customer WHERE id=1;
SELECT * FROM order WHERE customer_id=1;

提示:如果你再次访问 $customer->orders ,并不会重复执行上述第2行SQL查询。这条查询语句只在表达式第一次被访问时才被执行。后续的访问将直接返回内部缓冲数据。如果你想重新执行查询,只需要先调用一下unset来清除缓存:

unset($customer->orders);.

有时候,你可能想传递参数给关联查询来限定查询条件。比如只想读取超过指定数额的大额订单,而不是所有订单。为此,可以使用如下getter方法来声明一个 bigOrders 关系:

class Customer extends \yii\db\ActiveRecord
{
 public function getBigOrders($threshold = 100)
 {
  return $this->hasMany(Order::className(), ['customer_id' => 'id'])
   ->where('subtotal > :threshold', [':threshold' => $threshold])
   ->orderBy('id');
 }
}

记住 hasMany() 返回对象是一个 yii\db\ActiveQuery ,因此ActiveQuery的方法都可以被用来定制这个关联查询。

通过上述声明,如果你访问 $customer->bigOrders, 它将只返回数额大于100的订单。如果想指定一个不同的限定值,使用如下代码:

$orders = $customer->getBigOrders(200)->all();

注意:关联方法返回一个 yii\db\ActiveQuery 实例。如果你以属性(类property)的方式来访问它,返回数据是一个 yii\db\ActiveRecord 实例、或者是ActiveRecord数组或为空(null)。比如, $customer->getOrders() 返回一个 ActiveQuery 实例,而$customer->orders 返回一个 Order 对象数组(或者是一个空数组,如果查询结果为空)。

中间表关联查询

有时候,一些数据表通过中间表(pivot table)关联在一起。为了声明这样的关系,我们可以定制 yii\db\ActiveQuery 对象,通过调用它的 via() 或 viaTable() 方法。

比如,如果订单表 order 和商品表 item 通过连接表 order_item关联,我们可以在 Order 类中声明 items 关系如下:

class Order extends \yii\db\ActiveRecord
{
 public function getItems()
 {
  return $this->hasMany(Item::className(), ['id' => 'item_id'])
   ->viaTable('order_item', ['order_id' => 'id']);
 }
}

via() 方法和 viaTable() 类似,不过第一个参数是在当前ActiveRecord类中声明的一个关系(relation)名,而不是中间表的名称。比如,上述 items 关系也可以用下面的方法进行声明:

class Order extends \yii\db\ActiveRecord
{
 public function getOrderItems()
 {
  return $this->hasMany(OrderItem::className(), ['order_id' => 'id']);
 }
 public function getItems()
 {
  return $this->hasMany(Item::className(), ['id' => 'item_id'])
   ->via('orderItems');
 }
}

希望本文所述对大家基于Yii框架的PHP程序设计有所帮助。

PHP 相关文章推荐
PHP脚本的10个技巧(3)
Oct 09 PHP
用session做客户验证时的注意事项
Oct 09 PHP
PHP动态变静态原理
Nov 25 PHP
php session 错误
May 21 PHP
php的字符串用法小结
Jun 08 PHP
php中选择什么接口(mysql、mysqli)访问mysql
Feb 06 PHP
解析php中static,const与define的使用区别
Jun 18 PHP
PHP连接MySQL的2种方法小结以及防止乱码
Mar 11 PHP
Codeigniter实现智能裁剪图片的方法
Jun 12 PHP
PHP中读取文件的8种方法和代码实例
Aug 05 PHP
ThinkPHP独立分组使用的注意事项
Nov 25 PHP
简述php环境搭建与配置
Dec 05 PHP
php 实现301重定向跳转实例代码
Jul 18 #PHP
PHP的openssl加密扩展使用小结(推荐)
Jul 18 #PHP
PHP多进程编程总结(推荐)
Jul 18 #PHP
php 指定范围内多个随机数代码实例
Jul 18 #PHP
php 解决substr()截取中文字符乱码问题
Jul 18 #PHP
Yii2中cookie用法示例分析
Jul 18 #PHP
PHP socket 模拟POST 请求实例代码
Jul 18 #PHP
You might like
PHP输出数组中重名的元素的几种处理方法
2012/09/05 PHP
PDO版本问题 Invalid parameter number: no parameters were bound
2013/01/06 PHP
php安装xdebug/php安装pear/phpunit详解步骤(图)
2013/12/22 PHP
php7安装yar扩展的方法详解
2017/08/03 PHP
thinkphp5.1框架实现格式化mysql时间戳为日期的方式小结
2019/10/10 PHP
css动画效果之animation的常用样式
2021/03/09 HTML / CSS
JavaScript的document对象和window对象详解
2010/12/30 Javascript
js 优化次数过多的循环 考虑到性能问题
2011/03/05 Javascript
window.location.href中url中数据量太大时的解决方法
2013/12/23 Javascript
jQuery中index()的用法分析
2014/09/05 Javascript
nodejs URL模块操作URL相关方法介绍
2015/03/03 NodeJs
jquery插件jquery.LightBox.js实现点击放大图片并左右点击切换效果(附demo源码下载)
2016/02/25 Javascript
利用Javascript实现BMI计算器
2016/08/16 Javascript
利用vueJs实现图片轮播实例代码
2017/06/03 Javascript
关于使用js算总价的问题
2017/06/23 Javascript
微信小程序自定义头部导航栏(组件化)
2019/11/15 Javascript
JavaScript Tab菜单实现过程解析
2020/05/13 Javascript
jquery实现点击左右按钮切换图片
2021/01/27 jQuery
Python中使用glob和rmtree删除目录子目录及所有文件的例子
2014/11/21 Python
Python中实现对Timestamp和Datetime及UTC时间之间的转换
2015/04/08 Python
如何用itertools解决无序排列组合的问题
2017/05/18 Python
Python 脚本实现淘宝准点秒杀功能
2019/11/13 Python
python时间与Unix时间戳相互转换方法详解
2020/02/13 Python
解决pytorch多GPU训练保存的模型,在单GPU环境下加载出错问题
2020/06/23 Python
高清屏下canvas重置尺寸引发的问题的解决
2019/10/14 HTML / CSS
伦敦剧院门票:From The Box Office
2018/06/30 全球购物
中餐厅主管的职责范文
2014/02/04 职场文书
职业生涯规划书范文
2014/03/10 职场文书
关于祖国的演讲稿
2014/05/04 职场文书
乡镇爱国卫生月活动总结
2014/06/25 职场文书
人大调研汇报材料
2014/08/14 职场文书
党的群众路线教育实践活动个人对照检查材料
2014/09/22 职场文书
Python可变集合和不可变集合的构造方法大全
2021/12/06 Python
Redis监控工具RedisInsight安装与使用
2022/03/21 Redis
腾讯云服务器部署前后分离项目之前端部署
2022/06/28 Servers
Python绘制散点图之可视化神器pyecharts
2022/07/07 Python