Yii2 - 与多列有很多关系
Yii2 - hasMany relation with multiple columns
我有一个 table 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
查询。有人知道怎么做吗?
对于此查询
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]);
您不能以这种方式创建常规关系 - Yii 将无法为预先加载映射相关记录,因此它不支持这种方式。你可以找到一些解释 int this answer and related issue on GitHub.
根据用例,您可以尝试两种方法来获得类似的东西:
1。两个正则关系和getter简化访问
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 这将 return 两个关系的结果,所以你可以通过 $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()
将 return ActiveQuery
和 $model->messageThreads
模型数组。
为什么 orOnCondition()
不起作用
orOnCondition()
and 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
.
连接
我有一个 table 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
查询。有人知道怎么做吗?
对于此查询
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]);
您不能以这种方式创建常规关系 - Yii 将无法为预先加载映射相关记录,因此它不支持这种方式。你可以找到一些解释 int this answer and related issue on GitHub.
根据用例,您可以尝试两种方法来获得类似的东西:
1。两个正则关系和getter简化访问
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 这将 return 两个关系的结果,所以你可以通过 $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()
将 return ActiveQuery
和 $model->messageThreads
模型数组。
为什么 orOnCondition()
不起作用
orOnCondition()
and 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
.