API 文档中指定
这些ActiveQuery属性有什么区别,什么情况下应该使用
- 的关系列表
- 此查询应与 joined$joinWith
- 此查询应与执行的关系列表$with
$joinWith
和
$with
?
joinWith
使用
JOIN
将关系包含在原始查询中,而
with
则不包含。为了进一步说明,请考虑具有关系
Post
的类
comments
,如下所示:
class Post extends \yii\db\ActiveRecord {
...
public function getComments() {
return $this->hasMany(Comment::className(), ['post_id' => 'id']);
}
}
使用
with
以下代码:
$post = Post::find()->with('comments');
产生以下 sql 查询结果:
SELECT `post`.* FROM `post`;
SELECT `comment`.* FROM `comment` WHERE post_id IN (...)
而下面的
joinWith
代码:
$post = Post::find()->joinWith('comments', true)
查询结果:
SELECT `post`.* FROM post LEFT JOIN `comment` comments ON post.`id` = comments.`post_id`;
SELECT `comment`.* FROM `comment` WHERE post_id IN (...);
因此,当使用
joinWith
时,您可以按关系排序/过滤/分组。您可能需要自己消除列名称的歧义。参考:
http://www.yiiframework.com/doc-2.0/guide-db-active-record.html#lazy-eager-loading
with
和
joinWith
之间的区别
with
方法会产生以下 SQL 查询
$users = User::find()->with('userGroup');
SELECT * FROM `user`;
SELECT * FROM `userGroup` WHERE userId = ...
...使用
joinWith
时将导致此 SQL 查询
$users = User::find()->joinWith('userGroup', true)
SELECT * FROM user LEFT JOIN `userGroup` userGroup ON user.`id` = userGroup.`userId`;
所以当我需要过滤或搜索相关表中的数据时,我使用
joinWith
。其他信息
docu -> http://www.yiiframework.com/doc-2.0/guide-db-active-record.html#joining-with-relations 会告诉你:
“使用关系数据库时,常见的任务是连接多个表并将各种查询条件和参数应用于 JOIN SQL 语句。而不是显式调用 yii\db\ActiveQuery::join() 来构建 JOIN 查询,您可以重用现有的关系定义并调用 yii\db\ActiveQuery::joinWith() 来实现此目标。”
这意味着,你现在可以自己处理joins
、
innerJoins
、
outerJoins
以及 Yii2 中所有相关的好东西了。Yii(不是 Yii2)仅使用
join
而不是让用户决定连接类型。关于“Join”的详细信息 -> 它是基于 SQL 的东西。您可以在这里阅读相关内容 http://en.wikipedia.org/wiki/Join_(SQL)
joinWith()
的精彩答案之外,每当你想使用
joinWith()
并且列名不明确时,Yii / ActiveRecord 似乎会自动选择一个随机列,而不是您通常期望的内容(最左边的表)。最好通过指定类似
SELECT
的内容来指定
$query->select("post.*")
子句中最左边的表。我从一些内表中获取 id,它们的使用方式就像是从最左边的表中获取的,直到我弄清楚这一点。另一点需要注意的是,您可以为 joinwith 关系指定一个别名,因此您可以这样说:
$post->find()
->joinWith(["user u"])
->where(["u.id"=>$requestedUser->id])
->select("post.*")
->orderBy(["u.created_at"=>SORT_DESC]);
$query = MiniAppRisk::find()->joinWith(['country','text','riskType'])->orderBy(['risk_publish_date' => SORT_DESC]);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 10,
'page' =>1
],
]);
sql1
:
SELECT `fmm_text_risk_t`.risk_id FROM `fmm_text_risk_t`
LEFT JOIN `fmm_text_risk_target_t` ON `fmm_text_risk_t`.`risk_id` = `fmm_text_risk_target_t`.`risk_id`
LEFT JOIN `country` ON `fmm_text_risk_target_t`.`country_id` = `country`.`id`
LEFT JOIN `fmm_text_t` ON `fmm_text_risk_t`.`text_id` = `fmm_text_t`.`text_id`
LEFT JOIN `fmm_text_risk_type_relation_t` ON `fmm_text_risk_t`.`risk_id` = `fmm_text_risk_type_relation_t`.`risk_id`
ORDER BY `risk_publish_date` DESC LIMIT 10
与Yii2代码:
$query = MiniAppRisk::find()->with(['country','text','riskType'])->orderBy(['risk_publish_date' => SORT_DESC]);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => [
'pageSize' => 10,
'page' =>1
],
]);
sql2
SELECT DISTINCT * FROM `fmm_text_risk_t` ORDER BY `risk_publish_date` DESC LIMIT 10 ;
SELECT * FROM `fmm_text_risk_target_t` WHERE `risk_id` IN (5563, 5562, 5561, 5560, 5559, 5558, 5557, 5556, 5555, 5554);
SELECT * FROM `country` WHERE `id` IN (7, 165, 1, 20);
SELECT * FROM `fmm_text_t` WHERE `text_id` IN (15272, 15271, 15270, 15269, 15268, 15267, 15266, 15265, 15264, 15263);
SELECT * FROM `fmm_text_risk_type_relation_t` WHERE `risk_id` IN (5563, 5562, 5561, 5560, 5559, 5558, 5557, 5556, 5555, 5554);
...more
看来joinWith生成的SQL更少,效率更高。但是,使用 joinWith 进行分页时要小心。当你检查它们的执行结果时,你会发现每页的条目数少于 10 个。27680
27680
27900
27900
27900
30099
30099
30301
30301
30489