You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Yii2的HasMany关联中添加指定CASE WHEN条件?

解决方案

要在Yii2的HasMany关联ON条件中加入你需要的CASE WHEN逻辑,有两种常用实现方式,可根据是否需要全局生效选择:

方式一:修改全局关联定义(永久生效)

如果所有用到TaskGoal的tasks关联的场景都需要该条件,直接修改模型里的关联方法:

// 在TaskGoal模型中
use yii\db\Expression;

public function getTasks()
{
    return $this->hasMany(Task::class, ['goal_id' => 'id'])
        ->onCondition(new Expression(
            'CASE WHEN {{%task}}.type = :type_personal AND {{%task}}.user_author_id != {{%user}}.id THEN {{%user}}.show_personal_task = 0 ELSE TRUE END',
            [':type_personal' => 'personal']
        ));
}

说明:

  • {{%task}}和{{%user}}是Yii2的表前缀占位符,会自动替换为你的实际表前缀,避免硬编码表名
  • onCondition()方法会把条件注入到LEFT JOIN的ON子句中,而非WHERE子句,完全匹配你的需求

方式二:在特定查询中动态添加条件(仅当前查询生效)

如果只想在某一次查询中应用该条件,不想修改全局关联,可在joinWith中使用回调:

// 业务逻辑中的查询代码
use yii\db\Expression;

$query = TaskGoal::find()
    // 确保user表已关联,根据你的实际关联关系调整,比如TaskGoal有user关联则加:->joinWith('user')
    ->joinWith(['tasks' => function($taskQuery) {
        $taskQuery->onCondition(new Expression(
            'CASE WHEN {{%task}}.type = :type_personal AND {{%task}}.user_author_id != {{%user}}.id THEN {{%user}}.show_personal_task = 0 ELSE TRUE END',
            [':type_personal' => 'personal']
        ));
    }])
    // 其他查询条件...
    ->all();

可选优化:用AND/OR替代CASE WHEN

你的CASE WHEN逻辑可以等价转换为更简洁的AND/OR组合,性能和效果一致,可读性可能更好:

// 替换Expression中的内容为:
new Expression(
    '({{%task}}.type != :type_personal OR {{%task}}.user_author_id = {{%user}}.id OR {{%user}}.show_personal_task = 0)',
    [':type_personal' => 'personal']
)

注意事项

  • 确保user表已被加入当前查询(比如通过joinWith('user')或直接join),否则会报表不存在的错误
  • 如果你的关联使用了自定义别名,需要把表达式中的{{%task}}/{{%user}}替换为实际别名

内容的提问来源于stack exchange,提问作者Mexalim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 06:19:54