【问题标题】:How to realize Yii2 relation through string not array?如何通过字符串而不是数组来实现 Yii2 关系?
【发布时间】:2018-05-14 23:37:45
【问题描述】:

我有一个名为 ChatMessage 的类。 DB 中有 2 个主要列(from_user、to_user)。我想将这两列之一与用户模型 ID 相关联。如何使用看起来像这样的关系查询

public function getChattedUser()
{
    return $this->hasOne(User::className(), '(case when(chat_message.from_user={Yii::$app->user->id}) then chat_message.to_user else chat_message.from_user END)=user.id');
}

【问题讨论】:

  • 如果您在表模式中添加了约束,在生成模型时您应该在生成的模型中定义getFromUsergetToUser 关系,它们不满足您的要求吗?正如我所看到的,您正在尝试获取与当前登录用户聊天的用户数量

标签: string yii2 relation


【解决方案1】:

简短回答:这是不可能的

ActiveRecord 关系比您想象的要复杂,并且以可靠的方式支持这些条件确实很复杂/不可能。问题是关系可能在不同的上下文中使用:

  1. 加入select * from chat_messages join users on users.id = chat_messages.from_user
  2. 延迟加载select * from users where users.id = 1.
  3. 渴望加载select * from users where users.id IN (1, 2, 3, 4)

正如您所见,很难将您的on 条件转换为适合这三种类型的查询 (see this issue at GitHub)。

您可以尝试覆盖 ActiveQuery 以支持您的条件,但更简单(并且可能已经足够好)的是使用两个关系并创建一些帮助器以更方便地访问这些关系:

public function getUserFrom() {
    return $this->hasOne(User::className(), ['id' => 'user_from']);
}

public function getUserTo() {
    return $this->hasOne(User::className(), ['id' => 'user_to']);
}

public function getUser() {
    return Yii::$app->user->id == $this->user_from ? $this->userFrom : $this->userTo;
}

触发预加载:

ChatMessage::find()->with(['userFrom', 'userTo'])->all();

对于简单的情况应该足够了。对于更复杂的场景,您需要手动编写查询。


请注意,在您的模型中使用 Yii::$app->user->id 被视为不好的做法:

总之,模型 /.../

  • 不应直接访问请求、会话或任何其他环境数据。这些数据应该由控制器注入 模型;

https://www.yiiframework.com/doc/guide/2.0/en/structure-models#best-practices

【讨论】:

    【解决方案2】:

    您可以通过在关系函数中添加 if 语句来实现它。只需在 if 语句中编写case 逻辑,如下所示:

    public function getChattedUser()
    {
        if ($this->from_user == Yii::$app->user->id) {
            return $this->hasOne(User::className(), ['id' => 'to_user']);
        }
        return $this->hasOne(User::className(), ['id' => 'from_user']);
    }
    

    【讨论】:

    • 我没有投反对票,但这看起来不是最佳解决方案,您可以在关系中使用case,这一定是有人投反对票的原因,尽管在stackoverflow上的这个yii2社区中,我知道正如您在 javascript 论坛和其他人中看到的那样,这些人不会在没有任何正当理由的情况下投反对票,但应该有人留下评论,以便您纠正错误
    • 此选项创建 n+1 个问题。我的意思是只对关系进行一个 Mysql 查询
    猜你喜欢
    • 2012-09-07
    • 1970-01-01
    • 1970-01-01
    • 2017-12-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-01
    • 1970-01-01
    • 2022-12-06
    相关资源
    最近更新 更多