Laravel Eloquent关联模型能否使用upsert?如何处理父级ID填充问题?
Laravel 8
upsert关联父ID自动填充问题解决方案 问题根因
Laravel的upsert方法属于底层批量SQL操作,和create()/createMany()等单条/批量写入方法的实现逻辑不同:后者会自动读取关联关系中预设的父级外键值,自动填充到子模型字段中,但upsert为了保证批量操作的性能,直接生成原生UPSERT语句执行,不会自动遍历插入数据填充外键字段,因此会出现调用关联方法执行upsert但parent_id没有自动填充的情况。
可行方案:手动注入父级ID,无需避开该使用场景
这种场景完全可以正常使用upsert,只需要提前把父级ID手动合并到待插入的每一条数据中即可,示例代码如下:
// 先获取当前父模型的主键值 $parentId = $this->getKey(); // 遍历待写入的子模型数据,统一注入parent_id字段 $childUpsertData = collect($yourRawChildData)->map(function ($item) use ($parentId) { return array_merge($item, ['parent_id' => $parentId]); })->toArray(); // 执行upsert操作,和原调用逻辑一致 $this->childmodel()->upsert( $childUpsertData, [/* 子模型的唯一标识字段,例如 order_no 等 */], [/* 冲突时需要更新的字段,可选参数 */] );
该方案的优势
- 没有额外的数据库查询开销,仅在数组层面做字段合并,完全保留
upsert批量操作一次SQL的性能优势 - 逻辑简单可维护,符合Laravel官方针对批量操作的推荐处理方式
- 兼容性强,Laravel 8及以上所有支持
upsert的版本都可以通用
不推荐的替代方案
不要为了自动填充外键,把批量upsert拆分为多次单条写入(例如循环调用updateOrCreate),这种写法会产生N次SQL请求,数据量较大时性能损耗非常明显,完全失去了upsert的设计价值。
内容的提问来源于stack exchange,提问作者GatesPlan
相关产品推荐
相关产品推荐

