发现 ORM 方法 MorphToMany 的一个 Bug

person表
id integer
name string
address_rel表
id integer
lsc integer (11 or 101) 此处在 MorphMap 定义映射关系
lid integer
address integer
address表
id integer
country integer 国家ID
province integer 省ID
city integer 市区ID
….. 省略

首先,在AppServiceProvider我定义了morphMap:

Relation::morphMap([
    '11' => Person::class,
    '101' => Company::class,
]);

然后,在Person模型中,定义了获取所有地址的方法:

public function address()
{
    return $this->morphToMany(
        Address::class,  //地址表
        'lsc',  //多态关联表中的映射表关系
        'address_rel',  //多态关联表
        'lid', //映射表ID
        'address' //地址ID
    );
}

最后,在 Controller 层,来获取 Person 的所有地址:

$person = Person::find(1);
$person->address->toArray();

此时报错信息为:

"SQLSTATE[42S22]: Column not found: 1054 Unknown column 'lu_address_rel.lsc_type' in 'field list' (SQL: select `lu_address`.*, `lu_address_rel`.`lid` as `pivot_lid`, `lu_address_rel`.`address` as `pivot_address`, `lu_address_rel`.`lsc_type` as `pivot_lsc_type` from `lu_address` inner join `lu_address_rel` on `lu_address`.`id` = `lu_address_rel`.`address` where `lu_address_rel`.`lid` = 56 and `lu_address_rel`.`lsc_type` = 11)"

通过上面可以看到,我们传的 lsc 在 Laravel 中自动拼上了 _type,而 lid 是正确的,这时我们通过追查源码发现

发现 ORM 方法 MorphToMany 的一个 Bug
如上图所示,在我们传入 $foreignPivotKey 字段时,Laravel 做了相应的判断处理,如果传了这个字段(也就是 lid),则完全使用用户传入的值,否则将拼接为 $name . ‘_id’ ,这里的 $name 就是我们在 Model 中传入的第二个参数

那么我们接着来看 $name 参数是如何处理的

发现 ORM 方法 MorphToMany 的一个 Bug
追查到这里发现,Laravel 是直接将用户传入的 $name 参数拼上了 _type ,这就出现了上面的报错信息。

通过以上信息发现我们如果要用到 MorphToMany 方法,就必须要把表设计改为 Laravel 的规范,否则,目前的 Laravel 版本中用 MorphToMany 是完成不了需求的。

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
讨论数量: 4

我靠,那链接不就是我的么。。。 :grin:

5年前 评论
邢闯洋 (楼主) 5年前
黑将军

或许不能算bug吧,只是扩展性差,确实用这个得按照laravel标准来设计表,不方便,之前也打算用MorphToMany,也是遇到相同的问题

5年前 评论
邢闯洋 (楼主) 5年前

发现wx群友一枚 :smile:

5年前 评论

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