一对多关联需在“一”方用hasMany、“多”方用belongsTo配对定义,方法名须与with()一致,外键和主键非默认时需显式传参,create()自动填外键而save()需手动设置。

一对多关联必须在“一”方模型里写 hasMany,在“多”方模型里写 belongsTo,方向反了就查不到数据。
hasMany 和 belongsTo 必须配对写在两个模型里
只在 User 模型写 posts() 方法,Post 模型不写 user(),调用 $post->user 就会返回 null 或报错。Eloquent 不自动推导反向关系,两边都得明确定义。
-
hasMany写在“一”方(如User),返回集合,方法名要和你在with()里用的字符串一致(比如with('posts')对应public function posts()) -
belongsTo写在“多”方(如Post),返回单个实例,方法名也要匹配($post->user要求有public function user()) - 两个方法都必须是
public,且返回 Eloquent 关系实例(不能return null或 echo 东西)
外键字段名不是 user_id 怎么办
默认约定是找 posts.user_id,但如果你的字段叫 author_id 或 cat_id,就必须显式传参,否则关联失效——$user->posts 始终空数组,$post->user 始终 null。
-
User::class里的hasMany(Post::class, 'author_id')—— 第二个参数指定外键 -
Post::class里的belongsTo(User::class, 'author_id')—— 同样传第二个参数,保持一致 - 如果主键不是
id(比如是uid),还得补第三个参数:belongsTo(User::class, 'author_id', 'uid')
预加载 with() 为什么还是 N+1
写了 with('posts') 却发现 SQL 还是一条条发,大概率是关联方法名拼错了,或者模型没加 use Illuminate\Database\Eloquent\Model; 导致关系类没正确返回。
- 检查
with('posts')的字符串是否和User模型里public function posts()完全一致(大小写、下划线都不能错) - 嵌套预加载如
with('posts.user'),要确保Post模型真有叫user()的方法,漏定义就静默跳过 - 只查部分字段时,
select()必须包含外键(如select('id', 'title', 'author_id')),否则 Eloquent 分组失败,关联数据丢失
create() 和 save() 填外键的逻辑完全不同
create() 会自动把外键(如 user_id)塞进新记录;save() 不会,得自己设好,否则直接报 Integrity constraint violation。
- 安全写法:
$user->posts()->create(['title' => 'Hello'])—— 外键由框架自动填 - 不安全写法:
$post = new Post(['title' => 'Hello']); $user->posts()->save($post)——$post->user_id是空的,必须手动赋值 - 批量存多个:
$user->posts()->saveMany([$post1, $post2]),前提是每个$postN都已设好外键,或模型$fillable包含该字段
最常被忽略的是:外键字段在数据库里设了 NOT NULL,但模型没开放 $fillable 或用了 guarded = ['*'],这时 create() 看似成功,实则外键没写进去,后续查询全失效。


















