必须设置 $keytype = 'string' 且 $incrementing = false,否则 uuid 等字符串主键会导致 find() 查不到、路由绑定 404、关联查询为空、json 输出异常;二者必须同时配置,与迁移字段类型严格一致。

必须改 $keyType,否则字符串主键查不到、路由绑定 404、JSON 输出错乱——这不是可选项,是类型安全硬要求。
为什么 $keyType 不设就会查不到数据
当你用 find('abc-123') 查询 UUID 主键时,Eloquent 默认按整型处理:内部会把字符串 'abc-123' 强转成 0,然后执行 WHERE id = 0。数据库里当然没有这条记录,返回 null,也不报错,极难排查。
-
$keyType = 'string'会让whereKey()、findOrFail()、路由隐式绑定(Route::get('/users/{user}') → User::findOrFail($user))全部走字符串比较逻辑 - 不设时,
with('profile')关联也可能因类型不匹配返回空——比如外键是字符串,但模型$keyType还是默认int,底层 SQL 生成的WHERE profile.user_id = 0就错了 - API 返回 JSON 时,
id字段可能被 PHP 自动转成科学计数法(如123e45),或截断为0,前端解析失败
$incrementing = false 和 $keyType = 'string' 必须一起用
这两个属性是强耦合的。只要主键不是数据库 auto_increment 的整数(UUID、订单号、编码字符串),就必须同时设置:
-
$incrementing = false:禁用 Eloquent 对自增 ID 的所有假设——save()不跳过主键字段,create()不尝试读取lastInsertId(),批量插入不会丢掉你给的值 -
$keyType = 'string':确保所有基于主键的查询、序列化、绑定都按字符串处理,避免隐式转换 - 漏掉任一个,常见表现:
$user->id是null(但数据库已写入)、find('xxx')返回null、分页next_page_url里 ID 变成0
迁移文件和模型声明必须严格对应
数据库字段类型、模型属性、实际赋值方式三者不一致,是翻车高发区:
- 迁移中用了
$table->uuid('id')->primary(),模型里却没设$keyType = 'string'→ 路由绑定失败 - 迁移中用了
$table->string('code', 32)->primary(),但模型里只写了$primaryKey = 'code',漏了$incrementing = false和$keyType = 'string'→create()后$model->code为空 - 手动赋值主键时(如
$user->code = Str::random(16)),必须确保$incrementing = false,否则save()会忽略它
最易被忽略的一点:关联关系里外键比较也依赖 $keyType。比如 Post::with('author') 中,User 模型若主键是字符串但没设 $keyType,Eloquent 仍会拿整型去比对,导致 author 始终为空——这个坑不打日志、不报错,只能靠查 SQL 日志才能发现。











