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 相关文章推荐
整理的9个实用的PHP库简介和下载
Nov 09 PHP
PHP中的session永不过期的解决思路及实现方法分享
Apr 20 PHP
php启用sphinx全文搜索的实现方法
Dec 24 PHP
经典PHP加密解密函数Authcode()修复版代码
Apr 05 PHP
php编程每天必学之表单验证
Mar 01 PHP
thinkPHP实现将excel导入到数据库中的方法
Apr 22 PHP
PHP根据session与cookie用户登录状态操作类的代码
May 13 PHP
Yii针对添加行的增删改查操作示例
Oct 18 PHP
PHP中file_put_contents追加和换行的实现方法
Apr 01 PHP
php分页查询mysql结果的base64处理方法示例
May 18 PHP
php+jQuery实现的三级导航栏下拉菜单显示效果
Aug 10 PHP
PHP标准库(PHP SPL)详解
Mar 16 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 adodb分页实现代码
2009/03/19 PHP
PHP 一个随机字符串生成代码
2010/05/26 PHP
解决PHP程序运行时:Fatal error: Maximum execution time of 30 seconds exceeded in的错误提示
2016/11/25 PHP
laravel学习笔记之模型事件的几种用法示例
2017/08/15 PHP
JScript中的"this"关键字使用方式补充材料
2007/03/08 Javascript
javascript的trim,ltrim,rtrim自定义函数
2008/09/21 Javascript
js 返回时间戳所对应的具体时间
2010/07/20 Javascript
js 获取class的元素的方法 以及创建方法getElementsByClassName
2013/03/11 Javascript
jquery中ajax函数执行顺序问题之如何设置同步
2014/02/28 Javascript
浅谈JavaScript Math和Number对象
2015/01/26 Javascript
javascript模拟map输出与去除重复项的方法
2015/02/09 Javascript
jquery使整个div区域可以点击的方法
2015/06/24 Javascript
jquery遍历json对象集合详解
2016/05/18 Javascript
AngularJS基础 ng-class-odd 指令示例
2016/08/01 Javascript
WEB 前端开发中防治重复提交的实现方法
2016/10/26 Javascript
详解js中==与===的区别
2017/01/08 Javascript
js+html获取系统当前时间
2017/11/10 Javascript
fetch 使用及如何接收JS传值
2017/11/11 Javascript
nodejs爬虫初试superagent和cheerio
2018/03/05 NodeJs
Vue CL3 配置路径别名详解
2019/05/30 Javascript
js JSON.stringify()基础详解
2019/06/19 Javascript
[00:12]DAC2018 no[o]ne亮相SOLO赛 他是否如他的id一样无人可挡?
2018/04/06 DOTA
python设置值及NaN值处理方法
2018/07/03 Python
Python文件读写保存操作的示例代码
2018/09/14 Python
基于python plotly交互式图表大全
2019/12/07 Python
pytorch GAN伪造手写体mnist数据集方式
2020/01/10 Python
Keras Convolution1D与Convolution2D区别说明
2020/05/22 Python
canvas因为图片资源不在同一域名下而导致的跨域污染画布的解决办法
2019/01/18 HTML / CSS
巴黎卡诗加拿大官网:Kérastase加拿大
2018/11/12 全球购物
打造完美自荐信
2014/01/24 职场文书
伦敦奥运会口号
2014/06/13 职场文书
反洗钱宣传活动总结
2014/08/26 职场文书
党支部创先争优承诺书
2014/08/30 职场文书
2015年项目经理工作总结
2015/04/30 职场文书
安全知识竞赛主持词
2015/06/30 职场文书
2015年秋季学校开学标语
2015/07/16 职场文书