数据库+模型 - AR模型关系定义 ¶
作者:KK
发表日期:2016.12.22
修改日期:2017.01.24 补充跨数据库的关系声明
获取一对多关联表的数据 ¶
AR模型提供了一种面向对象的操作方法让我们获取关联表,这回我拿用户和发表文章来说说
如果在Yii里查用户发表的文章,这样的代码是很菜的行为,我并不建议这样写:
$user = User::findOne($userId);
$articles = Article::findAll(['user_id' => $user->id]);
foreach($articles as $article){
echo $article->title . '<br/>';
}
通过getter定义关系 ¶
基于本文章的例子,官方推荐我们在User
模型里建立一个getter方法来获取所有文章(在Object 基类的特性里有介绍过getter嘛,怕你忘了我提醒一下)
这个getter是这样写的:
public function getArticles(){
$关联表的类名表的类名::className();
$关联表的字段表的字段'user_id';
$本表的字段'id';
return $this->hasMany($关联表的类名表的类名=> $本表的字段
这样的话就可以这样获取用户的所有文章了:
$user = User::findOne($userId); //查询一个用户的记录
foreach($user->articles as $article){ //扫描这个用户的文章
echo $article->title . '<br/>';
}
这样的代码看上去是不是更加有可读性?至少让调用代码变得更短了
你可能会觉得这样有点装饰花哨,但根据一个用户的ID去查他的各种关联数据的场景是经常有的,如果定义了getter就能在调用时简写一点了,而且代码也非常有可读性,语义简练
我解析一下这个hasMany
方法,它是用在一对多的两张关联表
场景里的,用户表有id字段,article表有user_id字段来关联用户,每条user表的记录里的用户都可以在article表里有多条文章记录
最终hasMany方法返回的是一个AR查询器,当使用这个查询器时底层和Article::findAll一样也实现了获取所有文章
hasMany的第一个参数就是要关联的表名;第2个参数就是关联关系(关联数组),这个关系中,本表的字段要放在$value部分
才可以
一对一关系 ¶
上手一对多关系表的模型查询后,咱们还要把一对一也给收拾一下其实已经很简单了,也是在Article模型里定义getUser
这样的一个getter:
public function getUser(){
//下面把hasMany换成hasOne hasOne hasOne 好了我说三遍了
$本表的字段'user_id';
$关联表的字段表的字段'id'; //注意下面,把关联表的字段放在key那里
return $this->hasOne(User::className(), [$关联表的字段表的字段=> $本表的字段//这样获取文章所属的用户就方便了:
echo $article->user->name;
只要将之前学会的hasMany方法换成hasOne就行了,参数是一样的
延迟加载 ¶
$user = User::findOne(1);
$articles = $user->articles; //触发getArticles
其实此时还没有发生SELECT * FROM article WHERE user_id = $用户ID
这样的查询,只是getArticles方法返回了一个AR查询器
当你真正要用起这个查询器相关的数据时,它才会查询给你,比如count($articles)
的话它就会去查了,所以这叫延迟加载
那既然它还没查询,其实我们还能做我们喜欢的事情,由于它是一个AR查询器,而AR查询器又跟Query查询器类似,所以可以这样玩:
$user = User::findOne(1);
$articles = $user->articles->andWhere(['>', 'click', 5])->limit(10)->all();
通过andWhere方法追加条件,再加个limit 10篇文章最后才进行查询也可以
跨数据库关系声明 ¶
这个会很少用吧,但比较容易明白所以顺便讲讲
我们目前讲到的AR模型默认就是指yii\db\ActiveRecord,这是基于主流SQL关系数据库层面上定义的AR模型,其实还有一种AR模型就是yii\mongodb\ActiveRecord(需要安装yii-mongodb扩展),下面代码中的两个模型可以实现互相定义关系获取对方的数据(基于官方示例代码稍作了修改):
//Customer表对应的AR模型,假设在MySql里
class Customer extends \yii\db\ActiveRecord
{
public static function tableName(){
return 'customer';
}
public function getComments(){
//声明与comment的一对多关系
return $this->hasMany(Comment::className(), ['customer_id' => 'id']);
}
}
// Comment是在mongoDb里的comment集合
class Comment extends \yii\mongodb\ActiveRecord //注意继承{
public static function collectionName(){
return 'comment';
}
public function getCustomer(){
//声明与customer的一对一关系
return $this->hasOne(Customer::className(), ['id' => 'customer_id']);
}
}
$customer = Customer::findOne(1);
echo count($customer->comments); //输出评论数,底层会构造与mongoDb之间的查询处理
$comment = Comment::findOne(99);
echo $comment->customer->name; //输出客户名称
关于Yii里用mongoDb的AR模型,有需要的请去翻一下官方资料,我暂时未计划写这部分,至少我对mongoDb也不是很熟悉