
本文共 3933 字,大约阅读时间需要 13 分钟。
Laravel 6 模型关系精讲
一对一关系
正向关联
在 Laravel 中,一对一关系(One-to-One)是非常常见的关联类型,适用于一个用户拥有唯一的手机号码这种情况。我们可以通过 hasOne
方法来定义这样的关系。
定义关联:
在
User
模型中添加如下方法:public function phone(){ return $this->hasOne('App\Phone');}public function phone(){ // 如果你想要自定义外键名称,可以传第二个参数 return $this->hasOne('App\Phone', 'foreign_key');public function phone(){ // Eloquent 会根据模型的 `primaryKey` 假设外键字段的名称。如果需要自定义,可以传第三个参数 return $this->hasOne('App\Phone', 'foreign_key', 'local_key');}
使用方法:
$user = User::find(1);$phone = $user->phone; // 获取用户关联的手机号
如果
Phone
模型没有找到对应的记录,则会返回null
。关联,默认模型:
可以使用
withDefault
方法,为关联关系提供一个默认的模型实例:return $this->hasOne('App\Phone')->withDefault();
或者,如果你需要为默认模型补充额外的数据:
return $this->hasOne('App\Phone')->withDefault([ 'name' => '游客']);
反向关联
在涉及一对一关系的子模型中,你需要定义一个 belongsTo
关联。例如,在 Phone
模型中,告诉 Eloquent 上级模型是 User
。
public function user(){ return $this->belongsTo('App\User');}
使用方法相同,可以直接通过关联获取用户的信息。
$phone = Phone::find(1);$user = $phone->user;
一对多关系
一对多关系(One-to-Many)常用于类似博客文章与评论的场景。一个博客文章可能有多个评论。
正向关联
在 Post
模型中定义 comments
关联:
public function comments(){ return $this->hasMany('App\Comment');}
使用方法:
$post = Post::find(1);$comments = $post->comments;
如果你想对评论进行筛选,可以在关系上附加条件:
$comments = Post::find(1) ->comments() ->where('title', 'foo') ->first();
反向关联:
在
Comment
模型中定义:public function post(){ return $this->belongsTo('App\Post');}
关联默认模型
如果你需要为反向关联提供一个默认的模型,可以使用 withDefault
方法:
return $this->belongsTo('App\Post')->withDefault();
多对多关系
多对多(Many-to-Many)关系通常用于一个用户拥有的多个角色,而一个角色可以被多个用户拥有。这种关系需要一个中间表(Intermediate Table),一般命名为字母顺序结合两个模型的命名,例如 role_user
。
正向关联
在 User
模型中定义:
public function roles(){ return $this->belongsToMany('App\Role');}
反向关联
在 Role
模型中定义:
public function users(){ return $this->belongsToMany('App\User');}
多态关联
多态关联(Polymorphic Relations)允许一个模型同时关联到不同的模型类型,比如一个评论可以关联到文章或视频。
数据库设计
通常会有以下表结构:
表名 | id | title | ... | |
---|---|---|---|---|
posts | id | title | ... | |
videos | id | title | ... | |
comments | id | body | commentable_id | commentable_type |
在 Comment
模型中定义:
public function commentable(){ return $this->morphTo();}
在 Post
和 Video
模型中定义:
public function comments(){ return $this->morphMany('App\Comment', 'commentable');}
使用方法
$comment = Comment::find(1);$commentable = $comment->commentable;
如果 $commentable
是 Post
类型,你可以继续调用其它方法。
自定义多态关联类型字段
如果中间表需要额外的字段,可以通过 using
方法定义自定义关联类:
public function users(){ return $this->belongsToMany('App\User')->using('App\UserRole');}
多对多关联
多对多(Many-to-Many)关系适用于多个模型通过中间表关联。例如,博客的 Post
和 Video
可以共享 Tag
的关联。
数据库设计
表名 | id | name | |
---|---|---|---|
posts | id | name | |
videos | id | name | |
tags | id | name | |
taggables | tag_id | taggable_id | taggable_type |
在 Post
模型中定义:
public function tags(){ return $this->morphToMany('App\Tag', 'taggable');}
在 Tag
模型中定义:
public function posts(){ return $this->morphedByMany('App\Post', 'taggable');}public function videos(){ return $this->morphedByMany('App\Video', 'taggable');}
关联数据计数
如果你需要统计关联数据,可以使用 withCount
方法:
$posts = App\Post::withCount('comments')->get();
这样会在结果中添加 comments_count
字段。
遥层关联(Has Many Through)
与 Country
模型关联多个 Post
模型,可以通过中间的 User
模型:
public function posts(){ return $this->hasManyThrough('App\Post', 'App\User');}
延迟预加载
你可以在需要时懒加载关联:
$books = App\Book::all();if ($someCondition) { $books->load('author', 'publisher');}
插入与更新关联模型
保存:
$comment = new Comment(['message' => 'A new comment.']);$post = Post::find(1);$post->comments()->save($comment);
保存多条:
$post = Post::find(1);$post->comments()->saveMany([ new Comment(['message' => 'A new comment.']), new Comment(['message' => 'Another comment.'])]);
创建:
$post = Post::find(1);$comment = $post->comments()->create(['message' => 'A new comment.']);
多对多关联操作
附加:
$user = User::find(1);$user->roles()->attach($roleId);
移除:
$user->roles()->detach($roleId);
更新:
$user->roles()->save($role, ['expires' => $expires]);
连动父级时间戳
在 Comment
模型中定义:
protected $touches = ['post'];public function post(){ return $this->belongsTo('App\Post');}
这样,当一个 Comment
被保存或更新时,父级 Post
的 updated_at
时间戳会被自动更新。
发表评论
最新留言
关于作者
