模型关联给我们带来了哪些便利
@这是小豪的第二篇文章
上周已经给大家简单的介绍过 《 如何更快的找到自己所需的模型关联类型? 》,现在我们来了解一下,如何更好的发挥模型关联
所带给我们的便利。
小豪 Tip
with
、load
、attach
、detach
、sync
...... 当这些关键词第一次出现在我眼前的时候,我是一脸蒙的,不知道到底该如何去使用,更不知道他们到底与模型关联
存在着怎样的联系,就照着项目中原有的方式照搬,结果就是造成很多奇怪的问题,自己也活在混沌之中。所以在做之前得了解为什么要这样做!
今天的文章就是围绕着上面的几个关键词来展开的,从这几个关键词的中文解释中可以清晰的分为两类:查询、增删改,下面我们就来一一解读。
with
我们用文章和评论来举例:
class Comment extends Model
{
/**
* 获得拥有此评论的文章。
*/
public function post()
{
return $this->belongsTo('App\Post');
}
}
class Post extends Model
{
/**
* 获得与文章有关联的评论。
*/
public function comments()
{
return $this->hasMany('App\Comment');
}
}
从上篇文章中我们知道了如何通过文章获取评论,如下:
$comments = Post::find(1)->comments;
如果获取多篇文章的评论呢:
$posts = Post::all();
foreach ($posts as $post) {
foreach ($post->comments as $comment) {
echo $comment->content;
}
}
这个循环会执行一条语句去数据库查询所有的评论,然后为每一篇文章执行一条语句去获取评论。这个时候 with
就体现他的作用了:
$posts = Post::with('comments')->get();
foreach ($posts as $post) {
foreach ($post->comments as $comment) {
echo $comment->content;
}
}
在这次执行中,仅产生了两条语句:
select * from posts
select * from comments where comments.post_id in (1, 2, 3, 4, 5, ...)
这种方式叫渴求式加载
。有没有感觉性能优化就是如此的简单,哈哈。大家要记住 with
是得与模型关联
联系起来用的,如果 App\Post
中没有定义 comments
, with('comments')
是无法使用的噢。也可以在模型内部申明一个 with
数组,这样也也可以直接达到渴求式加载
的效果,就不用每次在查询语句中使用 with
了,一般直接在模型中 with
的数据是必须加载的数据,不必须的就别写在里面了,如下:
class Post extends Model
{
protected $with = [
'comments'
];
}
with
是可以接收数组的,像这样Post::with(['comments','nodes'])->get();
,需要注意的是with
不可接收空字符串,否则会报错,如果需要传空的话,传递一个空数组即可。with
还有很多用法的,大家可以在文档上面搜罗一番。
load
如果理解了
with
,那么load
就很好理解的,他们之间的区别就在于:load
是对已经查出的模型使用,立即加载某个关联关系,可以动态的加载关联数据,而with
是Laravel
帮你做好关联关系的查询,两者都是渴求式加载
,且查询的sql
是一模一样的 。
代码如下:
$posts = App\Post::all();
if ($someCondition) {
$posts->load('comments', 'nodes');
}
当关联关系没有被加载时,你可以使用使用 loadMissing 方法
,这是文档中给出的 loadMissing
的使用场景,其实刚开始看这句话的时候,我是不能理解的,既然关联关系没有被加载,我 load
一下不就行了吗?仔细了解一下之后发现,loadMissing
的主要作用是:加载从未加载过的关联,意思就是过滤了已经加载的关联。
到这里查询
基本上讲完了,细节还有一些具体的使用方法,大家可以细读文档,会发现不一样的惊喜。
下面讲的是:附加 / 分离 / 同步 ,他们有一个共同点就是所属的模型关联为
多对多关联
,简单点来说就是有中间表的那种关联。
attach
我们用用户和角色来举例:
class User extends Model
{
/**
* 用户的角色
*/
public function roles()
{
return $this->belongsToMany('App\Role');
}
}
class Role extends Model
{
/**
* 拥有此角色的用户
*/
public function users()
{
return $this->belongsToMany('App\User');
}
}
不太清楚这种关联模式的,先去看上一篇文章哦,我就不再解释
多对多关联
了。
顾名思义,attach
是就是“附加”的意思。单纯对这个案例来讲,大家或许就能想到,这里的附加就是用户与角色的关系附加到中间表去,Laravel
是如何处理的呢,现在来看一下:
$user = App\User::find(1);
$user->roles()->attach($roleId);
// 传递一组要插入到中间表中的附加数据
$user->roles()->attach($roleId, ['expires' => $expires]);
可以看到代码思路为:给指定用户的角色中附加一条新的角色。就是这么的清晰,哈哈。注意哦,这里是附加,主要是适用于添加关联的。
detach
有时也需要移除用户的角色。可以使用 detach
移除多对多关联记录。detach
方法将会移除中间表对应的记录。
见代码:
$user = App\User::find(1);
// 移除用户的一个角色...
$user->roles()->detach($roleId);
// 移除用户的所有角色...
$user->roles()->detach();
关系分离很简单,过一下就好了。
sync
现在我们来看一下关系同步,你们可能会问,sync
与 attach
有什么区别 ?他们两个最大的区别在于一个是更新、添加另一个是只添加,不知道这样说大家能不能理解,现在我们来通过代码来理解:
$user = App\User::find(1);
// 步骤一:同步角色 2、3、4
$user->roles()->sync([2, 3, 4]);
// 步骤二:附加角色 1、2、3
$user->roles()->attach([1, 2, 3]);
从上面代码中如果我们进行这样的操作:
-
先执行 步骤一 再执行 步骤二 ,得出的结果是:
用户绑定的角色为:角色2
、角色3
、角色4
、角色1
、角色2
、角色3
-
先执行 步骤二 再执行 步骤一 ,得出的结果是:
用户绑定的角色为:角色2
、角色3
、角色4
-
当前数据表中已经存在用户绑定了
角色1
、角色2
、角色3
,当执行 步骤一 后,得出的结果是:
用户绑定的角色为:角色2
、角色3
、角色4
(其实这种情况和第二种是一样的 )
大家有没有发现,只要执行了 sync
之后,都是以 sync
的角色为主,原有角色绑定数据都移除了。所以现在大家是否了解 sync
了呢?哈哈。
结束语
已经讲完哒,文笔粗糙不知道能不能帮到大家,哈哈。有错误的地方还请大家指正一下。
本作品采用《CC 协议》,转载必须注明作者和本文链接
高认可度评论:
个人觉得需要强调一下
sync
会移除原有数据中不在本次sync
数组里的id改为
会不会好一点,这样能保证不会报错
支持下作者,排版清晰,看得出来认真。
个人觉得需要强调一下
sync
会移除原有数据中不在本次sync
数组里的id@JasonG 嗯呢是的,忘记强调这个点了,谢谢大佬提醒
改为
会不会好一点,这样能保证不会报错