多表关联一对一查询之hasOne
public function actionAbout() { $article = Article::findOne(1); $category = $article->hasOne('app\models\Category', ['id'=>'cate_id'])->one(); var_dump($category); }
上面的例子可以更加简便为:
public function actionAbout() { $article = Article::findOne(1); $category = $article->hasOne(Category::className(), ['id'=>'cate_id'])->one(); var_dump($category); }
上面的例子hasOne()是直接写在控制器中的,如果需要多次用到此方法,会产生耦合,规范的写法是将此方法方法模型中:
模型中:
class Article extends ActiveRecord { public function getCategory() { $category = $this->hasOne(category::className(), ['id'=>'cate_id'])->one(); return $category; } }
控制器中:
public function actionAbout() { $article = Article::findOne(1); $category = $article->getCategory(); var_dump($category); }
hasOne()第二种写法:
模型中:
class Article extends ActiveRecord { public function getCategory() { $category = $this->hasOne(category::className(), ['id'=>'cate_id'])->asArray(); return $category; } }
控制器中:
public function actionAbout() { $article = Article::findOne(1); $category = $article->category; var_dump($category); }
PS:通过调用category属性,会自动走__get()魔术函数,__get()会自动补上get,变成getCategory(),并且会自动判断到hasOne()在结尾加上one(),所以模型里不需要加one()也行,最后返回结果。
上面的例子都是获取的一篇文章对应的分类,项目中我们常常都是获取每一篇文章对应的分类:
模型中:
class Article extends ActiveRecord { public function getCategory() { $category = $this->hasOne(category::className(), ['id'=>'cate_id'])->asArray(); return $category; } }
控制器中:
public function actionAbout() { $articles = Article::find()->all(); foreach ($articles as $article) { $category[] = $article->category; } var_dump($category); }
PS:这种方法执行sql次数为下面次数之和:
$articles = Article::find()->all(); //执行1次 foreach ($articles as $article) { $category[] = $article->category; //有多少篇文章执行多少次sql }
上例性能优化:
模型中:
class Article extends ActiveRecord { public function getCategory() { $category = $this->hasOne(category::className(), ['id'=>'cate_id']); return $category; } }
控制器中:
public function actionAbout() { $articles = Article::find()->with('category')->asArray()->all(); var_dump($articles); }
PS:这种方法只执行一次sql语句,效率会大大提高。实际是使用了join查询。