Yii2中多表关联查询,0表关联查询实例分析

本文实例讲述了Yii2.0表关联查询的方法,获取关联数据可以像访问主表ActiveRecord对象的属性(property)一样简单,一个客户有多个订单,这是获取客户的订单

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

大家用实例来注解这一局地

你能够使用 ActiveRecord
来展按钮联合检查询(举个例子,从A表读取数据时把事关的B表数据也共同读出来),
在Active
Record中,获取涉及数据足以像访问主表ActiveRecord对象的性质(property)同样轻松。

表结构

比如,通过适当的涉及注明,你可以应用 $customer->orders 来取得一个Order 对象数组,代表该顾客下的订单。

当今有客户表、订单表、图书表、小编表,

要声澳优个涉及(relation),定义三个getter方法,该办法重临一个yii\db\ActiveQuery
对象,具有关联上下文音信,这样将只询问符合条件的连带数据。比方:

客户表Customer(id  customer_name)

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']);
 }
}

订单表Order(id  order_name       customer_id   book_id)

上述代码中的 yii\db\ActiveRecord::hasMany() 和
yii\db\ActiveRecord::hasOne() 是用来建立模型关系型数据库中的 一对多 以及
一对一
关联关系。比如,多少个顾客customer有七个订单orders,而一个订单具备或归属于三个顾客。四个法子均收到五个参数并回到一个yii\db\ActiveQuery 对象:

图书表(id  book_name       author_id)

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

作者表(id  author_name)

$link:
两张表之间的列关联。这得是一个数组。数组成分的键是 $class
所对应表的列名称,而数组成分的值是近些日子表明类的列名称。依靠表外键关联来定义这个关系是二个好的编程施行。

模型定义

成就上述证明后,就足以因而定义相应的getter方法来像访问对象属性一样猎取涉及数据:

上面是那4一律模型的定义,只写出当中的关联

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

Customer

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

class Customer extends \yii\db\ActiveRecord

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

{

升迁:要是你再一次访谈 $customer->orders
,并不会再一次实行上述第2行SQL查询。那条查询语句只在表明式第二次被访谈时才被施行。后续的拜访将一贯回到内部缓冲数据。要是你想重新推行查询,只需求先调用一下unset来驱除缓存:

//
那是获取客商的订单,由地点大家知晓那么些是一对多的关系,二个客户有多个订单

unset($customer->orders);.

public function getOrders()

一时候,你大概想传递参数给涉嫌查询来限制查询条件。比如只想读取超越钦赐数量的大数额订单,实际不是怀有订单。为此,能够利用如下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_id,关联主表的id字段

通过上述注明,若是您拜望 $customer->bigOrders,
它将只回去数额超越100的订单。假诺想钦点多少个不一的限定值,使用如下代码:

return $this->hasMany(Order::className(), [‘customer_id’ =>
‘id’]);

$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

举个例子,若是订单表 order 和商品表 item 通过连接表
order_item关联,我们能够在 Order 类中宣称 items 关系如下:

class Order extends \yii\db\ActiveRecord

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');
 }
}

public function getCustomer()

更加多关于Yii相关内容感兴趣的读者可查阅本站专项论题:《Yii框架入门及常用本事总括》、《php卓绝开采框架总计》、《smarty模板入门基础教程》、《php面向对象程序设计入门教程》、《php字符串(string)用法总计》、《php+mysql数据库操作入门教程》及《php常见数据库操作技艺汇总》

{

期待本文所述对我们基于Yii框架的PHP程序设计有着援救。

//一样第八个参数内定关联的子表模型类名

您大概感兴趣的稿子:

  • Yii2实现跨mysql数据库关联合检查询排序效能代码
  • Yii第22中学涉及查询简单用法示例
  • Yii2增加和删除改查之查询
    where参数详细介绍
  • Yii第22中学央银行使join、joinwith多表关联合检查询
  • YII2数据库查询推行
  • Yii第22中学多表关联合检查询hasOne
    hasMany的章程

//

return $this->hasOne(Customer::className(), [‘id’ =>
‘customer_id’]);

}

// 获取订单中具备图书

public function getBooks()

{

//同样第三个参数钦赐关联的子表模型类名

//

return $this->hasMany(Book::className(), [‘id’ => ‘book_id’]);

}

}

复制代码

Book

class Book extends \yii\db\ActiveRecord

{

// 获取图书的小编

public function getAuthor()

{

//同样第三个参数内定关联的子表模型类名

return $this->hasOne(Author::className(), [‘id’ =>
‘author_id’]);

}

}

复制代码

Author

class Autor extends \yii\db\ActiveRecord

{

}

复制代码

hasMany、hasOne使用

Yii第22中学的表之间的关系有2种,它们用来钦命七个模型之间的涉嫌。

一对多:hasMany

一对一:hasOne

回来结果:那三个措施的归来结果都为yii\db\ActiveQuery对象

首先个参数:所关联的模子的类名称。

其次个参数:是二个数组,当中键为所提到的模子中的属性,值为眼下模型中的属性。

论及的使用

今昔我们获得贰个顾客的具备的订单新闻

// 获取四个客商新闻

$customer = Customer::findOne(1);

$orders = $customer->orders;  //
通过在Customer中定义的涉及方法(getOrders())来收获那个客户的保有的订单。

复制代码

地点的两行代码会生成如下sql语句

SELECT * FROM customer WHERE id=1;

SELECT * FROM order WHERE customer_id=1;

复制代码

关联结果缓存

假如客商的订单改换了,大家再另行调用

$orders = $customer->orders;

复制代码

再也获得订单的时候你会意识未有成形。原因是只会在首先次施行$customer->orders的时候才会去数据Curry面查询,然后会把结果缓存起来,未来查询的时候都不会再实行sql。

那正是说一旦本身想再一次实践sql如何是好吗?能够实行

unset($customer->orders);

$customer->orders;

复制代码

接下来就足以从数据Curry面取多少了。

概念三个关系

一样,大家还足以在Customer里面定义四个关系。

如再次来到总量超过100的订单。

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’);

}

}

复制代码

论及的三种访谈形式

如下面的,即使使用

$customer->bigOrders

复制代码

将会获取超过100的装有的订单。假如要回去大于200的订单能够如此写

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

复制代码

从地点能够观望访谈三个涉及的时候有二种方法

例如以函数的法子调用,会回到一个 ActiveQuery
对象($customer->getOrders()->all())

只要以属性的秘技调用,会平昔再次来到模型的结果($customer->orders)

with的使用看如下代码,是取二个顾客的订单

// 执行sql语句: SELECT * FROM customer WHERE id=1

$customer = Customer::findOne(1);

//执行sql:SELECT * FROM order WHERE customer_id=1

$orders1 = $customer->orders;

//这一个不会试行sql,直接使用方面包车型地铁缓存结果

$orders2 = $customer->orders;

复制代码

比如明日大家要抽出九19个顾客,然后访谈每种客户的订单,从上边的打听大家兴许会写出如下代码

// 执行sql语句: SELECT * FROM customer LIMIT 100

$customers = Customer::find()->limit(100)->all();

foreach ($customers as $customer) {

// 执行sql: SELECT * FROM order WHERE customer_id=…

$orders = $customer->orders;

// 处理订单。。。

}

复制代码

只是,借使真要那样写的话,会在foreach的每种循环之中都实践一遍sql去数据Curry面查询数据。因为各类$customer对象都以不同的。

为了消除地点的问题 能够动用yii\db\ActiveQuery::with()。

里头width的参数为涉嫌的称谓,也就在model里面定义的getOrders,getCustomer中的orders和customer

// 先执行sql: SELECT * FROM customer LIMIT 100;

//               SELECT * FROM orders WHERE customer_id IN (1,2,…)

$customers = Customer::find()->limit(100)

->with(‘orders’)->all();

foreach ($customers as $customer) {

// 在那几个轮回的时候就不会再实施sql了

$orders = $customer->orders;

// …handle $orders…

}

复制代码

即使利用了select来钦定再次回到的列,必要求力保重返的列里面饱含所涉及的模子的涉及字段,否则将不会重回关联的表的Model

$orders = Order::find()->select([‘id’,
‘amount’])->with(‘customer’)->all();

// $orders[0]->customer 的结果将会是null

//
因为下面的select中绝非回去所涉嫌的模子(customer)中的钦点的涉嫌字段。

// 倘诺加上customer_id,$orders[0]->customer就可以重返正确的结果

$orders = Order::find()->select([‘id’, ‘amount’,
‘customer_id’])->with(‘customer’)->all();

复制代码

给with加过滤条件

询问一个顾客超越100的订单

//首先实施sql: SELECT * FROM customer WHERE id=1

$customer = Customer::findOne(1);

// 再实行查询订单的sql语句:SELECT * FROM order WHERE customer_id=1
AND subtotal>100

$orders =
$customer->getOrders()->where(‘subtotal>100’)->all();

复制代码

询问一百个顾客的,每一个客商的总合大于100的订单

// 上面包车型客车代码会试行sql语句:

// SELECT * FROM customer LIMIT 100

// SELECT * FROM order WHERE customer_id IN (1,2,…) AND
subtotal>100

$customers = Customer::find()->limit(100)->with([

‘orders’ => function($query) {

$query->andWhere(‘subtotal>100’);

},

])->all();

复制代码

在此处width的参数为数组,键为关联的名目,值为回调函数。

也正是说
对orders那一个关系重返的ActiveQuery,再实施一次$query->andWhere(‘subtotal>100’);

运用joinWith实行表关联

咱俩都知晓能够用join on来写七个表之间的涉及。先看看yii第22中学joinWit的宣示

joinWith( $with, $eagerLoading = true, $joinType = ‘LEFT JOIN’ )

$with 数据类型为字符串或数组,

如若为字符串,则为模型中定义的关系的名称(可以为子关联)。

借使为数组,键为model中以getXXX格式定义的关系,值为对那么些涉及的愈益的回调操作。

$eagerLoading 是或不是加载在$with中关系的模型的数码。

$joinType 联接类型,可用值为:LEFT JOIN、INNEWrangler JOIN,暗中同意值为LEFT JOIN

// 订单表和客商表以Left join的格局关联。

// 查找全部订单,并以顾客 ID 和订单 ID 排序

$orders =
Order::find()->joinWith(‘customer’)->orderBy(‘customer.id,
order.id’)->all();

// 订单表和客商表以Inner join的法门关联

// 查找全数的订单和书

$orders = Order::find()->innerJoinWith(‘books’)->all();

复制代码

// 使用inner join 连接order中的 books关联和customer关联。

// 并对custmer关联再一次开展回调过滤:找寻24小时内注册客商满含图书的订单

$orders = Order::find()->innerJoinWith([

‘books’,

‘customer’ => function ($query) {

$query->where(‘customer.created_at > ‘ . (time() – 24 * 3600));

}

])->all();

// 使用left join连接 books关联,books关联再用left join 连接 author关联

$orders = Order::find()->joinWith(‘books.author’)->all();

复制代码

在贯彻上,Yii 先推行满意JOIN查询条件的SQL语句,把结果填充到主模型中,
然后再为每一种关联推行一条查询语句, 并填充相应的涉嫌模型。

// Order和books关联 inner join ,但不到手books关联对应的数量

$orders = Order::find()->innerJoinWith(‘books’, false)->all();

复制代码


On条件

在概念关联的时候还足以钦点on条件

class User extends ActiveRecord

{

public function getBooks()

{

return $this->hasMany(Item::className(), [‘owner_id’ =>
‘id’])->onCondition([‘category_id’ => 1]);

}

}

复制代码

在joinWith中使用

//先查询主模型(User)的数目, SELECT user.* FROM user LEFT JOIN item
ON item.owner_id=user.id AND category_id=1

// 然后再依照关系条件查询相关模型数据SELECT * FROM item WHERE owner_id
IN (…) AND category_id=1

// 那多少个在询问的进程中都行使了 on条件。

$users = User::find()->joinWith(‘books’)->all();

复制代码

一经未有利用join操作,即选取的是with 或者直接以属性来访谈关联。今年on条件会作为where 条件。

// SELECT * FROM user WHERE id=10

$user = User::findOne(10);

复制代码


总结

首先供给在模型中定义好关系(如getOrders中的Orders为多个事关)

接下来在with或然joinWith中运用在模型中定义的关联。

里面在接纳关联的时候仍可以内定回调方法。

再有就是足以给涉嫌、with、joinWith内定where可能on条件

这一有些其实相当多,也会有一点乱,有个别效果与利益没说说完,如七个表关联、逆关联等。

最主题的操作也就大概是这么些。假设还会有哪些地点想打听的,能够回帖调换。