belongsTo 应写在外键所在模型(如 User 有 company_id 则在 User 中定义),hasOne 应写在被引用模型(如 Company 无外键但有 Profile 则在 Company 中定义)。
belongsTo 和 hasOne 什么时候用反了?
关系定义错最直接的表现是:查不到数据,或者报
错误。根本原因不是语法写错了,而是没想清楚“谁属于谁”。
一定写在“外键所在模型”里——比如
表有
,那就在
模型里写
写在“被引用模型”里——
没有外键指向
,但它可能有一个专属的
(一对一),那就写
别硬记“一”和“多”,先看数据库字段:哪个表存了对方的 ID,那个表的模型就用
whereHas 查询慢得像卡住?
因为
默认生成的是 EXISTS 子查询,如果关联表没加索引,或条件没走索引,几万条数据时延迟直接上秒级。
先确认外键字段是否加了索引——比如
必须有索引,否则
就是全表扫描
避免在
里写复杂逻辑,比如
,尽量拆成简单
真要查多个条件,优先考虑
(Laravel 10.42+)或提前
加载再用集合过滤,而不是全压给数据库
with 预加载报 “Undefined property: Illuminate\Database\Eloquent\Collection::$xxx”?
这是典型的访问方式错误:你用了
,但代码里写了
,而实际查出来的是空关系(比如 author 被删了),
是
,不是空集合。
不会改变模型属性的存在性,它只是预加载;
可能为
,必须判空再访问
别用
图省事——它掩盖了数据不一致问题;更稳妥的是在关联定义里加约束,比如
如果业务上要求“必须有 author”,就在迁移里加外键约束,并在模型里用
(Laravel 11+)让查询失败得更早
自定义外键名时,hasOne 和 belongsTo 参数顺序容易搞混
比如用户头像存在
表,字段是
和
,你要定义多态关联。这时候两个方法的参数意义完全不同:
的第二个参数是外键名:
的第二、三、四个参数才是关键:
——顺序是「外键」、「主键」、「类型字段」
漏传第四个参数(
)会导致多态失效,查出来全是 null;传错顺序(比如把
当成
)会匹配到错误模型
关联关系不是写完就能跑通的,真正卡住人的永远是外键语义没理清、索引没跟上、或者空值处理太随意。别急着套文档示例,先打开数据库看一眼字段怎么存的。
Call to undefined relationshipbelongsToUsercompany_idUserbelongsTo(Company::class)hasOneCompanyUserProfilehasOne(Profile::class)belongsTowhereHasposts.user_idwhereHas('user')whereHaswhereHas('user', fn ($q) => $q->whereRaw('...'))wherewithWhereHaswithwith('author')$post->author->name$post->authornullwith$post->authornulloptional($post->author)->name->whereNotNull('users.id')belongsTo(...)->isRequired()avatarsowner_idowner_typebelongsTobelongsTo(User::class, 'owner_id')hasOnehasOne(Avatar::class, 'owner_id', 'id', 'owner_type')$typeidowner_type