Yii2 - отношение hasMany с несколькими столбцами - PullRequest
0 голосов
/ 21 сентября 2018

У меня есть таблица message_thread:

id
sender_id
recipient_id

Я хочу объявить в моей модели User отношение, которое будет извлекать все потоки сообщений следующим образом:

SELECT *
FROM message_thread
WHERE sender_id = {user.id}
    OR recipent_id = {user.id}

Я пробовал следующее:

public function getMessageThreads()
{
    return $this->hasMany(MessageThread::className(), ['sender_id' => 'id'])
        ->orWhere(['recipient_id' => 'id']);
}

Но он генерирует запрос AND.Кто-нибудь знает, как это сделать?

Ответы [ 2 ]

0 голосов
/ 22 сентября 2018

Вы не можете создать регулярное отношение таким способом - Yii не сможет отобразить связанные записи для быстрой загрузки, поэтому он не поддерживает это.Вы можете найти некоторое объяснение в этом ответе и связанной с ним проблеме на GitHub .

В зависимости от варианта использования вы можете попробовать два подхода, чтобы получить что-то похожее:

1.Два обычных отношения и метод получения для упрощения доступа

public function getSenderThreads() {
    return $this->hasMany(MessageThread::className(), ['sender_id' => 'id']);
}

public function getRecipientThreads() {
    return $this->hasMany(MessageThread::className(), ['recipient_id' => 'id']);
}

public function getMessageThreads() {
    return array_merge($this->senderThreads, $this->recipientThreads);
}

Таким образом, у вас есть два отдельных отношения для потоков отправителя и получателя, так что вы можете использовать их напрямую с объединениями или активной загрузкой.Но у вас также есть getter, который будет возвращать результат как отношений, так что вы можете получить доступ ко всем потокам с помощью $model->messageThreads.

2.Поддельные отношения

public function getMessageThreads()
{
    $query = MessageThread::find()
        ->andWhere([
            'or',
            ['sender_id' => $this->id],
            ['recipient_id' => $this->id],
        ]);
    $query->multiple = true;

    return $query;
}

Это не настоящие отношения.Вы не сможете использовать его с активной загрузкой или для объединений, но он будет извлекать все пользовательские потоки в одном запросе, и вы все равно сможете использовать его как обычное отношение активной записи - $model->getMessageThreads() вернет ActiveQuery и $model->messageThreads массив моделей.


Почему orOnCondition() не будет работать

orOnCondition() и andOnCondition() предназначены для дополнительныхON условия, которые всегда будут добавлены к базовому условию отношения с использованием AND.Поэтому, если у вас есть отношение, определенное следующим образом:

$this->hasMany(MessageThread::className(), ['sender_id' => 'id'])
    ->orOnCondition(['recipient_id' => new Expression('id')])
    ->orOnCondition(['shared' => 1]);

Это сгенерирует условие следующим образом:

sender_id = id AND (recipent_id = id OR shared = 1)

Как вы можете видеть, условия, определяемые orOnCondition(), отделены от условия от отношенияопределены в hasMany(), и они всегда объединяются с использованием AND.

0 голосов
/ 22 сентября 2018

Для этого запроса

SELECT *
FROM message_thread
WHERE sender_id = {user.id}
    OR recipent_id = {user.id}

Вы можете использовать эти

$query = (new \yii\db\Query)->from("message_thread")
$query->orFilterWhere(['sender_id'=>$user_id])->orFilterWhere(['recipent_id '=>$user_id]);
...