Laravel5.5 对模型进行全局作用域限制后使用 hasManyThrough 模型关系时,若关联表作用域限制字段相同会报 MySQL 错误

版本 :laravel 5.5.44 /mysql 5.7
错误:mysql联表时存在相同字段未指定表名
场景:存在三个Model,分别为Script Channel News 三个模型均在boot方法中设置了全局作用域限制site_id为用户所属site_id

    $site_id = $user->site_id ?? 0;
    static::addGlobalScope('site_id', function(Builder $builder) use ($site_id) {
        $builder->where('site_id', $site_id);
    });

在Script中存在hasManyThrough模型关系

    public function channel(){
        return $this->hasManyThrough('App\Models\Channel', 'App\Models\News', $this->foreignKeyName, 'id', 'id', 'channel_id');
    }

调用$script->channel时报错如下:

"SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'site_id' in where clause is ambiguous (SQL: select channels.*, news.script_id from channels inner join news on news.channel_id = channels.id where news.deleted_at is null and news.script_id = 182 and channels.deleted_at is null and site_id = 262)"

查看日志发现好像所有的全局作用域在生成SQL语句时都不限定表名的,请问该如何解决?这是否属于laravel的bug?

《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
leo
最佳答案

(new static)->getTable()

4年前 评论
讨论数量: 4
Summer

报错的主要信息在:

Column 'site_id' in where clause is ambiguous

因为连表查询时两张表里都有 site_id,一般前面加上表名前缀即可避免,如:channels.site_id

belongsToMany 也有同样的问题

建议你把 addGlobalScope 里的 $builder 打印出来看看能不能用它来做判断,手动添加上所属的 Model 表名做前缀。

4年前 评论

@Summer

谢谢Summer,

站长大大真早 :flushed:
我有考虑过打印$builder 但是没找到什么有用的信息,
addGlobalScope时类的实例好像还没生成吧,没有办法使用getTable获取表名,
而且addGlobalScope是被我封装在Trait里的 所以想看看各位有没有什么更好的办法不用我手动指定表名

另外为什么laracasts现在没办法注册,进入论坛注册页面时提示我很快就可以发帖了[黑人问号脸] :joy:

4年前 评论
leo

(new static)->getTable()

4年前 评论

@leo 哇 我怎么没想到呢 傻了傻了 谢谢大佬!
总结一下解决方案 希望能方便遇到同样问题的同学
addGlobalScope时 直接限定表名可避免此类问题

$site_id = $user->site_id ?? 0;
static::addGlobalScope('site_id', function (Builder $builder) use ($site_id) {
    $builder->where((new static)->getTable() . '.site_id', $site_id);
 });

再次感谢楼上两位!

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!