В чем разница между $ 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]);