最近一直在看网上视频学习Yii2.0,刚学习了关联查询这一章,就把自己的学习笔记总结了一下。关联查询在实际中用的是比较多的,其实在关联查询中,还有几个小的知识点需要注意,比如:hasMany和hasOne,joinWith 和 with的区别等,如果有理解不正确的地方,欢迎指正!
1.表的关联设计
a)Customer表
—-id 用户ID
—-name 用户名
b)Order表
—-id 价格ID
—-customer_id 用户ID
—-price 价格
customer表中的id 和Order表中的 customer_id 是关联的
2.在models中的写法
a)在customer表中加上方法getOrders();(这个方法中的get是固定的,而Orders是可以随便取的,但是我们一般倾向于和表名一致);
public function getOrders(){
$orders=$this->hasMany(Order::className(),['customer_id'=>'id'])->asArray()->all();
return $orders;
}
b)在price表中加上方法getCustomer();
public function getCustomer(){
$customer=$this->hasOne(Customer::className(),['id'=>'customer_i d'])->asArray()->one();
return $customer;
}
注意:在两个模型类中,你会发现getOrders方法中用的是hasMany,而在getCustomer方法中用的是hasOne,他们有什么区别呢?
i.通过customer来查询order,一个顾客可能会有多个订单,所以就调用的是hasMany(),所以说,hasMany 就是用于一对多的情况;
ii.通过订单来查询顾客,一个订单只能属于一个顾客,所以就调用的是hasOne(),所以说,hasOne 就是用于一对一的情况;
3.在Controllers中调用的写法
a)通过顾客查询订单:
public function actionOrder(){
//查新顾客信息
$customer=Customer::find()->where(['name'=>'zhangsan'])->one();
//查询出张三对应的所有订单
$orders=$customer->getOrders();
var_dump($orders);
}
注意:以上$orders=$customer->getOrders();这行代码也可以写为:$orders=$customer->orders;(这个orders就是models中的getorders中的orders),不过如果这样写的话,model中的方法最后的all()或one,方法就不能调用了,因为我们这样用时,$orders=$customer->orders;它会根据我们model中的hasMany 和 hasOne在后边自动补全all 或 one.
b)通过订单查询顾客:
public function actionCustomer(){
//查询出订单
$order=Order::find()->where(['id'=>1])->one();
//查询出顾客
$cus=$price->getCustomer();
var_dump($cus);
}
c)其实在控制器中我们也可以直接写成以下形式:
public function actionOrder(){
$customer=Customer::find()->where(['name'=>'zhangsan'])->one();
$orders=$customer->hasMany(Price::className(),['customer_id'=>'id'])->asArray()->all();
$orders=$customer->getOrders();
}
就是把model中封装的那个方法直接写在控制器中,但是这样写有个缺陷,就是当我们的表名或关联字段发生改变的时候,就需要修改控制器,如果我们在多个控制器中都查询了,修改起来就比较复杂,封装在models中之后,就直接修改对应的model就ok了。
4.关联查询的性能问题
a)关联查询的多次查询
//查询出所有的customer
$customer=Customer::find()->all();//select * from customer
foreach($customers as $customer){
//把每个顾客对应的订单都查询出来
$orders[]=$customer->orders;//=>select * from order where customer_id =....如果是100个customer,就要调用100次查询
}
以上的写法,如果是100个顾客,就会查询数据库101次,查用户一次,根据用户查订单100次
b)优化
$customers=Customer::find()->with('orders')->all();
//这样优化之后,相当于:
select * from customer
select * from orders where customer_id in (....);
之前要查询101次的,现在只需要查询2次就可以了
注意:with 中的“orders”,也是model中的getOrders中的orders