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

Laravel Eloquent预加载嵌套关系时IN子句重复ID问题

Laravel Eloquent嵌套预加载时IN子句出现大量重复ID

环境

  • 操作系统:Windows 11 - WSL2(Ubuntu 20.04)
  • PHP:8.1
  • 技术栈:Laravel 9.22 | InertiaJS | Vue3
  • 数据库:mariadb:10.7.4
  • 本地Web服务器:nginx

问题描述

在Laravel项目中使用Eloquent进行嵌套关系预加载时,执行$user->load(['auth','page.articles'])或控制器中$group->load(['users.page.articles','page' => ['articles','cover']])这类语句,生成的SQL查询里IN子句包含大量重复ID(例如in (1,1,...))。

关键背景

  1. Page模型使用多态关联morphTo(对应字段pageable_id、pageable_type)
  2. 项目基于InertiaJS开发
  3. 所有模型通过自定义HasUuid trait使用UUID(非Laravel内置实现)

排查与解决思路

1. 修正自定义HasUuid trait的主键逻辑

自定义UUID实现如果没正确覆盖Laravel的主键核心方法,会导致Eloquent无法识别唯一ID,进而在预加载时重复收集ID。重点检查并补全以下逻辑:

  • 模型中需设置public $incrementing = false;,因为UUID不是自增类型
  • 确保trait正确实现getKeyType()返回string,getKeyName()返回你的UUID字段名
  • 确认bootHasUuid方法中生成UUID的逻辑正确

示例修正代码:

trait HasUuid
{
    protected static function bootHasUuid()
    {
        static::creating(function ($model) {
            if (! $model->getKey()) {
                $model->{$model->getKeyName()} = Str::uuid()->toString();
            }
        });
    }

    public function getKeyName()
    {
        return 'id'; // 替换为你的UUID字段实际名称
    }

    public function getKeyType()
    {
        return 'string';
    }

    public function isIncrementing()
    {
        return false;
    }
}

2. 校验多态关联的定义正确性

多态关联的morphTo如果关联名称或反向关联定义错误,会导致Eloquent预加载时无法正确分组模型,重复生成ID:

  • 确保Page模型的morphTo关联名称与数据库字段对应:
// Page模型
public function pageable()
{
    return $this->morphTo();
}
  • 关联的User、Group等模型需正确定义反向多态关联:
// User模型示例
public function page()
{
    return $this->morphOne(Page::class, 'pageable');
}

3. 预加载时手动对ID去重

如果上述调整后仍有问题,可在预加载闭包中强制对ID去重,让IN子句只保留唯一值:

// 针对user的page.articles预加载
$user->load([
    'auth',
    'page.articles' => function ($query) use ($user) {
        $uniquePageIds = collect($user->page->pluck('id'))->unique()->values()->toArray();
        $query->whereIn('page_id', $uniquePageIds);
    }
]);

// 针对group的嵌套预加载
$group->load([
    'users.page' => function ($query) {
        $query->distinct('id');
    },
    'users.page.articles',
    'page' => ['articles','cover']
]);

4. 升级Laravel版本

Laravel 9.22存在部分预加载相关的小bug,官方后续在9.x分支修复过关联预加载的ID收集逻辑,可尝试升级到同分支的最新稳定版。


内容的提问来源于stack exchange,提问作者Gaël Duval

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 12:37:09