Laravel/Eloquent关联术语及类属性含义咨询
核心术语澄清
先理清几个易混淆的术语:
- Parent Model(父模型):关联的发起方,关联字段存储在另一方模型中。比如
User hasOne Phone,User 就是父模型。 - Child Model(子模型):依赖父模型的模型,关联字段(如
user_id)存在于该模型内。比如上面的 Phone。 - Related Model(关联模型):当前模型要关联的目标模型。比如在 User 的
phone()方法里,Related 是 Phone;在 Phone 的user()方法里,Related 是 User。
各关联类型示例&属性取值
所有示例基于常见业务场景,属性取值为默认规则,自定义字段可手动指定。
1. 一对一关联(hasOne ↔ belongsTo)
场景:一个用户(User)对应一部手机(Phone),一部手机属于一个用户。
User 模型(hasOne)
// app/Models/User.php public function phone() { return $this->hasOne(Phone::class); }
hasOne 关联属性取值:
$parent:当前 User 实例(如User::find(1)返回的对象)$related:Phone模型类$foreignKey:默认user_id(父模型蛇形命名 + _id)$localKey:父模型主键,默认id
Phone 模型(belongsTo)
// app/Models/Phone.php public function user() { return $this->belongsTo(User::class); }
belongsTo 关联属性取值:
$parent:User模型类$related:当前 Phone 实例(如Phone::find(1)返回的对象)$child:Phone模型类$foreignKey:当前模型的关联字段,默认user_id$ownerKey:父模型主键,默认id
说明:关联字段 user_id 存储在 Phone 表中,hasOne 从父模型找子模型,belongsTo 从子模型找父模型。
2. 一对多关联(hasMany ↔ belongsTo)
场景:一个用户(User)有多篇文章(Post),一篇文章属于一个用户。
User 模型(hasMany)
// app/Models/User.php public function posts() { return $this->hasMany(Post::class); }
hasMany 关联属性取值:
$parent:当前 User 实例$related:Post模型类$foreignKey:默认user_id$localKey:默认id
Post 模型(belongsTo)
// app/Models/Post.php public function user() { return $this->belongsTo(User::class); }
belongsTo 属性取值同一对一场景,$foreignKey 是 Post 表的 user_id,$ownerKey 是 User 表的 id。
说明:hasMany 返回多个关联模型的集合,关联字段存储在子模型(Post)中。
3. 多对多关联(belongsToMany ↔ belongsToMany)
场景:一个用户(User)可拥有多个角色(Role),一个角色可被多个用户拥有,中间表为 user_role(含 user_id、role_id)。
User 模型(belongsToMany)
// app/Models/User.php public function roles() { return $this->belongsToMany(Role::class); }
belongsToMany 关联属性取值:
$parent:当前 User 实例$related:Role模型类$foreignKey:当前模型在中间表的字段,默认user_id$relatedKey:关联模型在中间表的字段,默认role_id$table:中间表名,默认按两个模型蛇形命名的字母顺序拼接,此处为user_role
Role 模型(belongsToMany)
// app/Models/Role.php public function users() { return $this->belongsToMany(User::class); }
属性取值:
$parent:当前 Role 实例$related:User模型类$foreignKey:role_id$relatedKey:user_id$table:user_role
说明:多对多通过中间表建立关联,两个模型无严格父/子区分,取决于关联发起方。
4. 跨层一对多关联(hasManyThrough)
场景:一个国家(Country)有多个用户(User),一个用户有多个订单(Order),需通过用户关联获取国家的所有订单。
Country 模型(hasManyThrough)
// app/Models/Country.php public function orders() { return $this->hasManyThrough(Order::class, User::class); }
hasManyThrough 关联属性取值:
$parent:当前 Country 实例$related:Order模型类$through:中间模型User类$firstKey:Country 在 User 表的关联字段,默认country_id$secondKey:User 在 Order 表的关联字段,默认user_id$localKey:Country 主键,默认id
说明:跨两层模型关联,直接从顶层模型(Country)获取底层模型(Order)的数据。
5. 多态一对一关联(morphOne ↔ morphTo)
场景:用户(User)和文章(Post)都可拥有一个头像(Avatar),头像属于某个具体模型。
Avatar 模型(morphTo)
// app/Models/Avatar.php public function imageable() { return $this->morphTo(); }
morphTo 关联属性取值:
$parent:当前 Avatar 实例$related:关联的目标模型(可能是 User 或 Post)$foreignKey:默认imageable_id$morphType:默认imageable_type(存储关联模型的类名,如App\Models\User)
User 模型(morphOne)
// app/Models/User.php public function avatar() { return $this->morphOne(Avatar::class, 'imageable'); }
morphOne 关联属性取值:
$parent:当前 User 实例$related:Avatar模型类$foreignKey:imageable_id$localKey:User 主键id$morphType:imageable_type
Post 模型(morphOne)
// app/Models/Post.php public function avatar() { return $this->morphOne(Avatar::class, 'imageable'); }
说明:多态关联让一个模型同时关联多个不同类型的模型,通过 _id 和 _type 两个字段区分关联目标。
6. 多态一对多关联(morphMany ↔ morphTo)
场景:用户(User)和文章(Post)都可拥有多个评论(Comment)。
Comment 模型(morphTo)
// app/Models/Comment.php public function commentable() { return $this->morphTo(); }
User 模型(morphMany)
// app/Models/User.php public function comments() { return $this->morphMany(Comment::class, 'commentable'); }
Post 模型(morphMany)
// app/Models/Post.php public function comments() { return $this->morphMany(Comment::class, 'commentable'); }
说明:与多态一对一致命区别是,morphMany 返回多个关联模型的集合,属性规则和 morphOne 一致。
7. 多态多对多关联(morphToMany ↔ morphedByMany)
场景:用户(User)和文章(Post)都可被多个标签(Tag)标记,一个标签可关联多个用户或文章。
User 模型(morphToMany)
// app/Models/User.php public function tags() { return $this->morphToMany(Tag::class, 'taggable'); }
Post 模型(morphToMany)
// app/Models/Post.php public function tags() { return $this->morphToMany(Tag::class, 'taggable'); }
Tag 模型(morphedByMany)
// app/Models/Tag.php public function users() { return $this->morphedByMany(User::class, 'taggable'); } public function posts() { return $this->morphedByMany(Post::class, 'taggable'); }
说明:中间表默认是 taggable_tag,包含 taggable_id、taggable_type、tag_id 三个字段,用来关联不同类型的模型和标签。
内容的提问来源于stack exchange,提问作者Kevin Wheeler

