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