Laravel Eloquent 关联
模型关联
Eloquent关联在模型中以方法的形式呈现,提供了强大的链式调用和查询功能。可以分为一对一、一对多、多对多、远程一对多、多态一对一、多态一对多、多态多对多、自定义几种。
一对一
用户 User 和手机 Phone 是关联模型,用户拥有手机,手机属于用户。
关联
<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class User extends Model
{//获取用户关联的手机public function phone(){return $this->hasOne('App\Phone');}
}
一旦定义了关联,就可以使用Eloquent的动态属性获取相关的记录,如下:
$phone = User::find(1)->phone;
Eloquent会基于模型决定外键名称,会自动假设 Phone 模型有一个 user_id 字段,如果想要覆盖这个决定,可以传递 hasOne 第二个参数,如下:
return $this->hasOne('App\Phone', 'foreign_key');
如果Eloquent外键值与父级id不匹配,可以传递 hasOne 第三个参数,如下:
return $this->hasOne('App\Phone', 'foreign_key', 'local_key');
反向关联
<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Phone extends Model
{//获得拥有此手机的用户public function user(){return $this->belongsTo('App\User');}
}
一对多
文章 Post 和评论 Comment 是关联模型,对一篇文章可以发表很多评论。
关联
<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Post extends Model
{//获取文章的评论public function comments(){return $this->hasMany('App\Comment');}
}
访问 Post 文章的 comments 的属性获取评论的集合,如下:
$comments = App\Comment::find(1)->comments();foreach ( $comments as $comment) {//}
还可以添加过滤,如下:
$comments = App\Comment::find(1)->comments()->where('title', 'xxx')->first();
反向关联
<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Comment extends Model
{//获取评论所属文章public function post(){return $this->belongsTo('App\Post');}
}
定义好之后,可以通过 Comment 模型的 post 动态属性来访问,如下:
$comment = App\Comment::find(1);
echo $comment->post->title;
多对多
用户 User ,角色 Role (中间模型为 UserRole )模型可以认为是多对多关联,用户可以有多个角色,每个角色可以为多个用户所有。对应的数据分别为 users ,roles ,role_user 。其中 role_user 是按两个模型字母排序,包含 user_id 和 role_id 两个字段。
关联
<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class User extends Model
{//用户的角色public funciton roles(){return $this->belongsToMany('App\Role');}
}
定义好 roles 动态属性后,可以获取用户的角色,如下:
$user = App\User::find(1);
foreach ( $user->roles as $role ) {//
}
也可以使用 roles 方法,如下:
$roles = App\User::find(1)->roles()->orderBy('name')->get();
如果关联表名不符合默认规则,可以传递 belongsToMany 第二个参数,如下:
return $this->belongsToMany('App\Role', 'role_user');
如果关联表两个字段不符合默认规则,可以传递 belongsToMany 第三个、第四个参数,如下:
return $this->belongsToMany('App\Role', 'role_user', 'user_id', 'role_id');
定义反向关联
<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Role extends Model
{//拥有此角色的用户public function users(){return $this->belongsToMany('App\User');}
}
取中间表字段
在获取关联对象后,可以使用模型的 pivot 访问中间表数据,如下:
$user = App\User::find(1);
foreach ( $user->roles as $role ) {echo $role->pivot->created_at;
}
默认情况下,pivot 只包含了两个模型的主键,如果中间表还有其它的字段,需要在关联时明确指出,如下:
return $this->belongsToMany('App\Role')->withPivot('column1', 'column2');
如果想自动维护中间表的 created_at 和 updated_at 时间戳,需在关联时附加 withTimestamps 方法:
return $this->belongsToMany('App\Role')->withTimestamps();
自定义中间表模型
<?phpnamespace App;use Illuminate\Database\Eloquent\Model;class Role extends Model
{public function users(){return $this->belongsToMany('App\User')->using('App\UserRole');}
}
自定义时 UserRole 模型,如下:
<?phpnamespace App;use Illuminate\Database\Eloquent\Relations/Pivot;class UserRole extends Pivot
{//...
}
远程一对多
国家 Country 有很多用户 User , 用户有很多博客 Post,对应的数据表结构如下:
countriesid:主键idname:国家名称...
usersid:主键idcountry_id:国家idname:姓名...
postsid:主键iduser_id:用户idtitle:博客题目...
代码实现:
<?phpnamespace App;use Illuminate\Database\Eloquent\Modell;class Country extends Model
{//获取一个国家下所有的博客public function posts(){return $this->hasManyThrough('App\Post', ‘App\User');}
}
当之后的参数不符合默认规则时,需要传递对应的参数,如下:
class Country extends Model
{public function posts(){return $this->hasManyThrough('App\Post','App\User','country_id','user_id','id','id'}
}
多态一对一
一对一的多态关联类似于简单的一对一关联,但目标模型在当个关联上属于多个其它模型。博客 Post ,用户 User 共享与图像 Image 模型的多态一对一关联。
数据表结构
postsid:主键title:标题body:文章内容...
usersid:主键title:姓名url:头像...
imagesid:主键body:图片imageable_id:关联主键imageable_type:关联模型...
images 表 imageable_id 存储博客或用户id,imageable_type 存储所属模型的类名。imageable_type 来决定我们访问关联模型时,要返回的父模型的类型。
模型结构
<?phpuse Illuminate\Database\Eloquent\Model;class Image extends Model
{//获取此图像所属的模型public function imageable(){return $this->morphTo();}
}class Post extends Model
{//获取此博客的图像public function image(){return $this->morphOne('App\Image', 'imageable');}
}class User extends Model
{//获取此用户的图像public function image(){return $this->morphOne('App\Image', 'imageable');}
}
获取多态关联
$posts = App\Post::find(1);
$image = $posts->image;$image = App\Image::find(1);
$imageable = $image->imageable;
多态一对多
一对多的多态关联类似于简单的一对多关联,但目标在单个模型上可以属于多个其它模型。文章 Post 和视频 video 的评论 comment 可以看作是一个一对多的多态关联。
数据表结构
postsid:主键...
videosid:主键...
commentsid:主键commentable_idcommentable_type...
comments 数据表 commentable_id 字段存储文章或视频的主键,commentable_type 存储所属模型的类名。commentable_type 来决定我们访问关联模型时,返回父模型的类型。
模型结构
<?phpuse Illuminate\Database\Eloquent\Model;class Comment extends Model
{//获取拥有此评论的模型public function commentable(){return $this->morphTo();}
}class Post extends Model
{//获取此文章的所有评论public function comments(){return $this->morphMany('App\Comment', 'commentable');}
}class Video extends Model
{//获取此视频的评论public function comments(){return $this->morphMany('App\Comment', 'commentable');}
}
获取多态关联
$posts = App\Post::find(1);
foreach ($posts->comments as $comment)
{//
}$comment = App\Comment::find(1);
$commentable = $comment->commentable;
多态多对多
文章 Post 和视频 Video 共享标签 Tag 模型。
数据表结构
postsid:主键...
videosid:主键...
tagsid:主键...
taggablestag_id:标签IDtaggable_id:关联模型IDtaggable_type:关联模型类名...
模型结构
<?phpuse Illuminate\Database\Eloquent\Model;class Post extends Model
{//获取文章标签public function tags(){return $this->morphToMany('App\Tag', ''taggable);}
}class Video extends Model
{//获取视频标签public function tags(){return $this->morphToMany('App\Tag', 'taggable');}
}class Tag extends Model
{//获取拥有此标签的文章public function posts(){return $this->morphedByMany('App\Post', 'taggable');}//获取拥有此标签的视频public function videos(){return $this->morphedByMany('App\Video', 'taggable');}
}
获取关联
$post = App\Post::find(1);
foreach ($post->tags as $tag)
{//
}$tag = App\Tag::find(1);
foreach($tag->videos as $video)
{//
}
查询关联关系是否存在
//获取至少有一条评论的文章
$posts = App\Post::has('comments')->get();//获取至少有三条评论的文章
$posts = App\Post::has('comments', '>=', 3)->get();//获取有一条评论的文章,并加载评论的投票信息
$posts = App\Post::has('comments.votes')->get();//获取至少有一条评论的文章,并且以foo开头
$posts = App\Post::whereHas(function ($query) {$query->where('content', 'like', 'foo%');
})->get();
关联计数
$posts = App\Post::withCount('comments')->get();
foreach ($posts as $post)
{echo $post->comments_count;
}$posts = App\Post::withCount('votes', 'comments' => function ($query) {$query->where('content', 'like', 'foo%');
})->get();
echo $posts[0]->votes_count;
echo $posts[0]->comments_count;$posts = App\Post::withCount(['comments','comments as pending_comments_count' => function ($query) {$query->where('approved', false);})])->get();
echo $posts[0]->comments_count;
echo $posts[0]->pending_comments_count;$posts = App\Post::select(['title','body'])->withCount('comments')->get();
echo $posts[0]->title;
echo $posts[0]->body;
echo $posts[0]->comments_count;
插入更新关联模型
保存方法
添加一个 Comment 到博客 *** Post*** 模型,可以不用在 Comment 中设置 post_id 属性,使用关联模型的 save 方法将 Comment 直接插入,如下:
$comment = new App\Comment(['message' => 'a message comment’]);
$post = App\Post::find(1);
$post->comments->save($comment);
如需要保存多个关联模型,可以使用 saveMany 方法,如下:
$post = App\Post::find(1);
$post->comments()->saveMany([new App\Comment(['message' => 'a comment']),new App\Comment(['message' => 'b comment'])
});
新增方法
create 方法接收普通的php数组,如下:
$post = App\Post::find(1);
$comment = $post->comments->create(['message' => 'a new comment'
});
createMany 可以创建多个关联模型:
$post = App\Post::find(1);
$post->comments->createMany([['message' => 'a new comment'],['message' => 'a new comment']
]);
更新belongsTo关联
当更新 belongsTo 关联时,可以使用 associate 方法。此方法将会在子模型中设置外键。
$account = App\Account(1);
$user->account->associate($account);
$user->save();
当移除 belongsTo 关联时,可以使用 dissociate 方法。此方法会将关联外键设置为 null 。
$user->account->dissociate();
$user->save();
默认模型
belongsTo 关系允许指定默认模型,当给定关系为 null 时,将会返回默认模型。
//获取博客的作者
public function user()
{return $this->belongsTo('App\User')->withDefault();
}
如果需要在默认模型里添加属性,可以传递数组或回调方法到 withDefault 方法中,如下:
//获取博客的作者
public function user()
{return $this->belongsTo('App\User')->withDefault(['name' => 'Guest Author']);
}public function user()
{return $this->belongsTo('App\User')->withDefault(function ($user) {$user->name = 'Guest Author';});
}
多对多关联
附加/分离
给某个用户添加一个角色是通过向中间表插入一条记录实现的,可以使用 attach 方法,如下:
$user = App\User::find(1);
$user->roles()->attach($roleId);
在将关系附加到模型时,还可以传递一组要插入中间表的附加数据,如下:
$user->roles()->attach($roleId, ['expires' => $expores]);
移除用户的角色,使用 detach 移除多对多关联记录,如下:
//移除用户的一个角色
$user->roles()->detach($roleId);//移除用户的所有角色
$user->roles()->detach();
为了方便,attach 和 detach 允许传递一个id数组,如下:
$user = App\User::find(1);
$user->roles()->detach([1,2,3]);
$user->roles()->attach([1 => ['expires' => $expires],2 => ['expires' => $expires]
]);
同步关联
sync 接收id数组以替换中间表的记录,所有未在id数组中的记录都会被移除,如下:
$user->roles()->sync([1,2,3]);
可以传递额外的附加数据到中间表,如下:
$user->roles()->sync([1 => ['expires' => $expires], 2,3);
如果不想移除现有的id,可以使用 syncWithoutDetaching 方法,如下:
$user->roles()->syncWithoutDetaching([1,2,3]);
Laravel Eloquent 关联相关推荐
- Laravel Eloquent关联模型查询设置查询条件与指定字段
我的个人博客:逐步前行STEP 1.直接获取关联模型: 1)在get中指定字段: $user->posts()->where('created_at','>',date('Y-m-d ...
- 深入理解 Laravel Eloquent(三)——模型间关系(关联)
Eloquent是什么 Eloquent 是一个 ORM,全称为 Object Relational Mapping,翻译为 "对象关系映射"(如果只把它当成 Database A ...
- Laravel Eloquent 小技巧
1. 获取原始属性 当修改一条Eloquent 模型记录的时候你可以通过调用getOriginal()方法获取记录的原始属性 $user = App\User::first(); $user-> ...
- Laravel 5.1 文档攻略——Laravel Eloquent ORM最强大也是最难理解的部分:数据关系...
简介 其实大家都知道,数据表之间都是可以关联的,Eloquent ORM是数据模型操作代替表操作,那么表的关联查询,在Eloquent这里也就是模型间的关联查询,这就是本章的主要内容: Eloquen ...
- Laravel Eloquent ORM 实例教程 —— 模型删除及软删除相关实现
1.删除模型 1.1 使用delete删除模型 删除模型很简单,先获取要删除的模型实例,然后调用delete方法即可: $post = Post::find(5); if($post->dele ...
- 20 个 Laravel Eloquent 必备的实用技巧
Eloquent ORM 看起来是一个简单的机制,但是在底层,有很多半隐藏的函数和鲜为人知的方式来实现更多功能.在这篇文章中,我将演示几个小技巧. 1. 递增和递减 要代替以下实现: $article ...
- PHP 项目中单独使用 Laravel Eloquent 查询语句来避免 SQL 注入
OWASP (Open Web Application Security Project) 是一个记录当前 web 应用所受威胁情况的项目.我一直都在关注他们的网站,从 2010,2013 和 201 ...
- 使用Laravel Eloquent ORM 时如何查询表中指定的字段
我们在使用Laravel ORM的Model方法find, get, first方法获取数据对象时返回的数据对象的attributes属性数组里会包含数据表中所有的字段对应的键值关系, 那么如何在OR ...
- laravel mysql注入_PHP 项目中单独使用 Laravel Eloquent 查询语句来避免 SQL 注入
OWASP (Open Web Application Security Project) 是一个记录当前 web 应用所受威胁情况的项目.我一直都在关注他们的网站,从 2010,2013 和 201 ...
- 使用Laravel Eloquent ORM 时如何查询表中指定的字段 1
我们在使用Laravel ORM的Model方法find, get, first方法获取数据对象时返回的数据对象的attributes属性数组里会包含数据表中所有的字段对应的键值关系, 那么如何在OR ...
最新文章
- IOS开发知识(七)
- SAP中国招聘内部顾问,工作职责是做客户项目,ABAP开发
- java开发13寸_Java 从入门到进阶之路(二十九)
- [BZOJ3566][SHOI2014]概率充电器
- 英特尔商用攻略升级:企业如何趟平信息化建设这条路?
- 了解和使用DotNetCore和Blazor中的异步编程
- [原创]JSLint-Toolkit v1.2 - Update with qooxdoo1.3
- brew 一直等待_等待高高时,可以做的小事...
- QThread Class
- Vue的三个点es6知识,扩展运算符表达含义
- 给FCKeditor添加自定义按钮的方法
- 怎样做小游戏挖金子(VC,源码3)
- delphi pi怎么得到?
- python爬取淘宝数据魔方_淘宝数据魔方技术架构解析读后感
- 海外 Android 三方应用市场
- c语言嵌入式系统修炼之道
- python3 x完全兼容_中国大学MOOC: Python 3.x 系列版本代码完全兼容 Python 2.x系列的既有语法。...
- C语言 —— 多维数组
- java用正则表达式判断字符串中是否仅包含英文字母、数字和汉字
- TiKV源码分析(一)RaftKV层
热门文章
- WhereDidMyTimeGo - 一款帮你记录每天的时间分配的MacOS app
- 控制台安装selenium运行浏览器报错TypeError: ‘module‘ object is not callable
- 关于日期插件在chrome中出现被遮挡的问题
- android7.1索尼,Xperia 1
- 使用谷歌(Google)TTS服务 – Java版开源gTTS及Python gTTS
- Milton 1.5.1发布,开源服务器端类库
- Cannot find name ‘console‘. Do you need to change your target library?ging the ‘lib‘ compiler option
- 马克飞象(markdown)的快捷键
- rxjava背压_关于RxJava背压
- first season tenth episode,Joey kissed Chandler!!!