Отношение Yii2 дублируется при использовании внутреннего соединения и Jeft соединения - PullRequest
0 голосов
/ 15 ноября 2018

Есть 3 модели с отношением между собой.Пример

class A extends ActiveRecord
{
    public static function tableName(){
        return 'tbl_a';
    }
    public function getB()
    {
        return $this->hasOne(B::className(), ['column' => 'column']);
    }
}

class B extends ActiveRecord
{
    public static function tableName(){
        return 'tbl_b';
    }
    public function getC()
    {
        return $this->hasOne(C::className(), ['column' => 'column']);
    }
}

У меня есть следующий код:

$result = A::find()->joinWith('b')->where('');
if () {
    A->joinWith('b.c')->where('');
}
$result->createCommand()->rawSql;

И результат у меня следующий sql:

select * from tbl_a left join tbl_b on ... join tbl_b on ... join tbl_c on ... where ...

Как вы можете видеть SQL-запрос дубликатов таблицы отношений 'tbl_b.Знаете почему?

ОБНОВЛЕНИЕ

ОК, я исследовал свою проблему более подробно.Соединение таблиц дублируется, если используются разные типы JOIN.Следующие оригинальные модели:

class Myuser extends ActiveRecord
{
    public static function tableName(){
        return 'myuser';
    }

    public function getProfile()
    {
        return $this->hasOne(Profile::className(), ['user_id' => 'id']);
    }
}

class Profile extends \yii\db\ActiveRecord {

    public static function tableName(){
        return 'profile';
    }

    public function getCity()
    {
        return $this->hasOne(City::className(), ['id'=>'city_id']);
    }
}

Выполненный код:

$get_city = 1;
$u = Myuser::find()->joinWith('profile', 0, 'INNER JOIN');
if ($get_city) {
    $u->joinWith('profile.city');
}
echo $u->createCommand()->rawSql;

Результат:

SELECT `myuser`.* FROM `myuser` 
    INNER JOIN `profile` ON `myuser`.`id` = `profile`.`user_id`
    LEFT JOIN `profile` ON `myuser`.`id` = `profile`.`user_id`
    LEFT JOIN `city` ON `profile`.`city_id` = `city`.`id`

Как избежать повторения, если мне нужно получить уникальную таблицу'profile' и добавьте поля из таблицы 'city'.Если в таблице 'city' нет полей, значение должно быть 'null'.

Ответы [ 2 ]

0 голосов
/ 16 ноября 2018

Это потому, что вы используете разные типы соединений для этих двух соединений.joinWith('profile', false, 'INNER JOIN') и joinWith('profile') будут генерировать разные JOIN (joinWith() использует LEFT JOIN в качестве типа соединения по умолчанию), поэтому у вас есть 2 соединения по вашему запросу.Если вы хотите избежать дубликатов, вы можете использовать одинаковые настройки для этих двух joinWith() вызовов:

$get_city = 1;
$u = Myuser::find()->joinWith('profile', false, 'INNER JOIN');
if ($get_city) {
    $u->joinWith('profile.city', false, 'INNER JOIN');
}
echo $u->createCommand()->rawSql;

Результат:

SELECT `myuser`.* FROM `myuser` INNER JOIN `profile` ON `myuser`.`id` = `profile`.`user_id` INNER JOIN `city` ON `profile`.`city_id` = `city`.`id`

Если вы хотите объединить INNER JOIN и LEFT JOIN, вы можете использовать расширенный синтаксис:

$get_city = 1;
if ($get_city) {
    $u = Myuser::find()->joinWith(
        [
            'profile' => function (ActiveQuery $query) {
                $query->joinWith('city');
            },
        ],
        false,
        'INNER JOIN'
    );
} else {
    $u = Myuser::find()->joinWith('profile', false, 'INNER JOIN');
}
echo $u->createCommand()->rawSql;

Результат:

SELECT `myuser`.* FROM `myuser` INNER JOIN `profile` ON `myuser`.`id` = `profile`.`user_id` LEFT JOIN `city` ON `profile`.`city_id` = `city`.`id`
0 голосов
/ 16 ноября 2018

Я думаю, это своего рода ошибка (или функция) в рамках. Когда вы используете отношение profile.city, фреймворк не видит отношения, уже присоединенного к inner join ... Я предполагаю, что если вы используете left join для первого отношения, все будет работать нормально.

В вашем случае попробуйте использовать leftJoin() и укажите имя таблицы для присоединения:

$get_city = 1;
$u = Myuser::find()->innerJoinWith('profile');
if ($get_city) {
    $u->leftJoin('city', 'profile.city_id = city.id');
}
echo $u->createCommand()->rawSql;
...