必须显式设置 $primaryKey 为真实主键字段名(如 'des_id'),非自增主键需设 $incrementing = false,字符串主键还需设 $keyType = 'string',关联关系须同步指定外键与主键字段名。

必须显式设置 $primaryKey,否则所有基于主键的操作(find()、findOrFail()、关联加载)都会默认查 id 字段,直接报错。
模型里怎么声明非 id 主键字段名
在模型类中加一行 protected $primaryKey = 'your_field_name';,字段名必须和数据库表里真实主键列名完全一致(包括大小写、下划线)。比如表里主键是 des_id,就写 'des_id';是 user_code,就写 'user_code'。
常见错误现象:
-
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'users.id'—— 模型没设$primaryKey,但数据库表根本没有id字段 -
find(123)返回 null,但数据明明存在 —— 字段名拼错,比如写了'user_id'实际是'usr_id'
主键不是自增整数时要关掉 $incrementing
只要主键不是数据库 auto_increment 的整数(比如 UUID、字符串编码、手动维护的订单号),就必须加 public $incrementing = false;。否则 save() 或 create() 会尝试生成或读取自增 ID,导致插入失败、ID 被覆盖或 SQL 报错。
典型场景:
- 用
uuid()做主键 → 必须设$incrementing = false - 用
bigInteger('order_no')->primary()但没开 auto_increment → 同样要关$incrementing - 迁移里用了
$table->id()但实际想手动赋值 → 也要关,否则 Laravel 仍会跳过你给的值
$keyType 不是可选项,是类型安全必需项
如果主键是字符串(UUID、VARCHAR 编码等),必须设 protected $keyType = 'string';。否则 Laravel 内部会把传入的 find('abc') 强转成整型 0,查不到数据也不报错。
影响点很具体:
- 路由隐式绑定(
Route::get('/posts/{post}', ...))会失效 -
whereKey()底层逻辑出错 - 关联查询时外键比较类型不匹配,
with('author')返回空
注意:$keyType 和 $incrementing 是联动的 —— 字符串主键几乎总是要同时设 false 和 'string'。
关联关系里主键不匹配的坑
Eloquent 关联(如 belongsTo()、hasMany())默认按 id 匹配,不会自动读取你设的 $primaryKey。所以如果你的 User 模型主键是 user_id,但没改配置,$post->user 就会去查 users.id,而不是 users.user_id。
解决方式分两种:
- 确保关联目标模型已正确定义
$primaryKey(最基础) - 外键字段名不遵循约定时,显式传参:
belongsTo(User::class, 'owner_code', 'user_id')—— 第二个参数是本表外键,第三个是对方主键字段名
多对多中间表也一样:两边模型的 $primaryKey 必须和中间表里的外键列名对得上,不然 sync() 会静默失败。
最容易被忽略的是:改了模型的 $primaryKey,但忘了同步调整迁移文件里的主键定义和外键约束。数据库层面没建对,Laravel 层再配也没用。


















