Yii2中使用join、joinwith多表关联查询

下面是这4个个模型的定义,只写出其中的关联

Customer

class Customer extends \yii\db\ActiveRecord { // 这是获取客户的订单,由上面我们知道这个是一对多的关联,一个客户有多个订单 public function getOrders() { // 第一个参数为要关联的子表模型类名, // 第二个参数指定 通过子表的customer_id,关联主表的id字段 return $this->hasMany(Order::className(), ['customer_id' => 'id']); } }

Order

class Order extends \yii\db\ActiveRecord { // 获取订单所属用户 public function getCustomer() { //同样第一个参数指定关联的子表模型类名 // 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使用

Yii2中的表之间的关联有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的时候才会去数据库里面查询,然后会把结果缓存起来,以后查询的时候都不会再执行sql。

那么如果我想再次执行sql如何做呢?可以执行

unset($customer->orders); $customer->orders;

然后就可以从数据库里面取数据了。

定义多个关联

同样,我们还可以在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;

如果现在我们要取出100个用户,然后访问每个用户的订单,从上面的了解我们可能会写出如下代码

// 执行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去数据库里面查询数据。因为每个$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

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/bec8dc6c3afcc308f85f7fd0c0b0a29f.html