В чем разница между $with и $joinWith в Yii2 и когда их использовать?
В документации API указано, что
$joinWith
- Список отношений, которые этот запрос должен соединить с$with
- Список отношений, с которыми этот запрос должен быть выполнен с
В чем разница между этими свойствами ActiveQuery и в какой ситуации мы должны использовать $joinWith
и $with
?
3 answers
Разница между 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
, когда мне нужно фильтровать или искать данные в связанных таблицах.
Дополнительная информация
Документ -> http://www.yiiframework.com/doc-2.0/guide-db-active-record.html#joining-with-relations расскажу вам об этом:
" При работе с реляционными базами данных общей задачей является объединение нескольких таблиц и применение различных условий и параметров запроса к инструкции SQL JOIN. Вместо явного вызова yii\db\ActiveQuery::join() для создания запроса на объединение, вы можете повторно использовать существующие определения отношений и вызвать yii\db\ActiveQuery::joinWith() для достижения этой цели."
Это означает, что вы способны справиться joins
, innerJoins
, outerJoins
и все хорошие связанные с этим вещи в Yii2 по теперь ты сам. Yii (не Yii2) использует только join
вместо этого, не позволяя пользователю решать о типе соединения. Подробнее о "Присоединении" -> это вещь, основанная на SQL. Вы можете прочитать об этом здесь http://en.wikipedia.org/wiki/Join_ (SQL)
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
Пожалуйста, обратите внимание, что в дополнение к приведенным выше удивительным ответам, которые помогли мне понять, как использовать joinWith()
, что всякий раз, когда вы хотите использовать joinWith()
и у вас неоднозначные имена столбцов, Yii/ActiveRecord автоматически выбирает случайный столбец вместо того, что вы обычно ожидаете (крайняя левая таблица). Лучше всего указать крайнюю левую таблицу в предложении SELECT
, указав что-то вроде $query->select("post.*")
. Я получал идентификаторы из некоторых внутренних таблиц, и они использовались так, как будто они были с крайнего левого стола, пока я не понял это.
Еще один момент, который следует отметить, заключается в том, что вы можете указать псевдоним для отношения joinwith, чтобы вы могли сказать что-то вроде:
$post->find()
->joinWith(["user u"])
->where(["u.id"=>$requestedUser->id])
->select("post.*")
->orderBy(["u.created_at"=>SORT_DESC]);