关于 拾年之璐

微信公众号知行校园汇,点击查看,欢迎关注

其他平台(点击蓝字可访问):

GitHub  |  Gitee  |  哔哩哔哩  |  语雀  |  简书  |  微信小程序  |  知行达摩院  

本文专栏:Laravel  点击查看系列文章

本文主要内容:

  • 10.1 关联概念
  • 10.2 一对一关联
  • 10.3 一对多关联
  • 10.4 多对多关联
  • 10.5 关联查询

10.1 关联概念

关联模型,即:两张或以上的表进行一定规则的绑定关联。

比如:

  • 一个学生(学生表)对应一张个人信息卡(信息表),这种就是一对一;
  • 一篇博文(帖子表)对应多个评论(评论表),这种就是一对多;
  • 一个用户(用户表)对应多个职位(权限表),而一个职位又可以有多个用户;那么,这种就是多对多关联;

当然,还有更多更复杂的关联,都是基于此的。

本文只探讨这三种基本的关联。

既然是关联,当然会有绑定的概念,当有数据库操作,关联表也会跟着变动;这就是关联模型的意义。

10.2 一对一关联

1、我们以下面的两张表为实例,进行演示:

左侧users主表主键为id。在Laravel中,主键默认是id。

右侧profiles附表,主键为id,外键为user_id。在laravel中,外键模式格式是主表名_主键

然后使用命令,创建两个表对应的模型model:User.phpProfile.php

php artisan make:model Models/User
php artisan make:model Models/Profile

然后给两个表生成注释

php artisan ide-helper:models

2、正向关联:在主表User.php中,写入关联附表Profile.php的代码,格式及参数解释,如下所示:

//User.php,一对一关联Profile 表
public function profile()
{//参数1 或:'App\Http\Models\Profile'//参数2:默认为user_id,如不是需要指明//参数3:默认id,如不是需要指明return $this->hasOne(Profile::class, 'user_id', 'id');
}

然后,即可在控制类中使用:

//注意:->profile 不要加括号,以属性方式访问
$profiles = User::find(19)->profile;
return $profiles;

输出结果:

{"id": 1,"user_id": 19,"hobby": "喜欢大姐姐","status": 1
}

在这个过程中,执行的SQL语句是两条,为:

select * from `laravel_users` where `laravel_users`.`id` = 19 limit 1
select * from `laravel_profiles` where `laravel_profiles`.`user_id` = 19 and `laravel_profiles`.`user_id` is not null limit 1

3、反向关联:在附表Profile.php中,写入关联主表User.php的代码,格式及参数如下所示:

public function user()
{//参数1 为主表类//参数2,3 和正向一致,默认对应可以不写return $this->belongsTo(User::class, 'user_id', 'id');
}

然后可以在控制类中使用:

$users = Profile::find(1)->user;
return $users;

输出结果:

{"id": 19,"username": "蜡笔小新","password": "123","gender": "男",......
}

在这个过程中,执行的SQL语句为:

select * from `laravel_profiles` where `laravel_profiles`.`id` = 1 limit 1
select * from `laravel_users` where `laravel_users`.`id` = 19 limit 1

10.3 一对多关联

1、我们以下面的两张表进行演示:

可以看出,这是一个一对多的关联。

同样,为表books 创建模型:

php artisan make:model Models/Book

并且生成注释:

php artisan ide-helper:models

2、正向关联:在主表User.php中,写入关联附表Book.php的代码,格式及参数解释,如下所示:

//正向,一对多关联Book 表
public function book()
{return $this->hasMany(Book::class, 'user_id', 'id');
}

然后,即可在控制类中使用:

//得到蜡笔小新所有关联的书籍列表
$books = User::find(19)->book;
return $books;

执行结果:

[{"id": 1,"user_id": 19,"title": "《莎士比亚》"},{"id": 10,"user_id": 19,"title": "《热情天堂》"},{"id": 11,"user_id": 19,"title": "《完美人生》"},{"id": 29,"user_id": 19,"title": "《哈利波特》"}
]

在这个过程中,执行的SQL语句是两条:

select * from `laravel_users` where `laravel_users`.`id` = 19 limit 1
select * from `laravel_books` where `laravel_books`.`user_id` = 19 and `laravel_books`.`user_id` is not null

3、获取一对多关联的数据,如果再进行筛选,可以使用下面方法:

$books = User::find(19)->book()->where('id',11)->get();
return $books;

执行结果为:

[{"id": 11,"user_id": 19,"title": "《完美人生》"}
]

执行的SQL为:

select * from `laravel_users` where `laravel_users`.`id` = 19 limit 1
select * from `laravel_books` where `laravel_books`.`user_id` = 19 and `laravel_books`.`user_id` is not null and `id` = 11

4、反向关联:在附表Book.php中,写入关联主表User.php的代码。和一对一的反向关联一致。

public function user()
{//参数1 为主表类//参数2,3 和正向一致,默认对应可以不写return $this->belongsTo(User::class, 'user_id', 'id');
}

然后在控制类中执行代码:

//一对多反向关联
$users = Book::find(1)->user;
return $users;

执行结果为:

{"id": 19,"username": "蜡笔小新","password": "123","gender": "男",......
}

执行的SQL为:

select * from `laravel_books` where `laravel_books`.`id` = 1 limit 1
select * from `laravel_users` where `laravel_users`.`id` = 19 limit 1

10.4 多对多关联

1、多对多关联,比前面两种要复杂一些,需要一张中间表,共三张;

我们以下面的 3 张表进行演示:

左表:.users:用户表

中表:.role_users:中间表,默认表名是这样的。然后两边互相关联的默认外键:user_id,role_id。

右表:.roles:权限表

对于这三张表,只需要创建用户表权限表的模型即可:

php artisan make:model Models/User
php artisan make:model Models/Role

同样,写入注释:

php artisan ide-helper:models

2、正向关联:在 User.php 设置多对多关联

//多对多关联
public function role()
{//参数1:同上//参数2:中间表名//参数3,4 如果是默认值,则可不传return $this->belongsToMany(Role::class, 'role_users', 'user_id', 'role_id');
}

Role.php留空。

然后即可在控制类中使用。比如多对多的关联输出:查看用户19都拥有哪些权限

$roles = User::find(19)->role;
return $roles;

输出结果:

[{"id": 2,"type": "评论审核专员","pivot": {"user_id": 19,"role_id": 2}},{"id": 3,"type": "图片监察员","pivot": {"user_id": 19,"role_id": 3}},{"id": 1,"type": "超级管理员","pivot": {"user_id": 19,"role_id": 1}}
]

多对多会生成一个中间字段:pivot,里面包含多对多的双id;

执行的SQL为:

select * from `laravel_users` where `laravel_users`.`id` = 19 limit 1select `laravel_roles`.*, `laravel_role_users`.`user_id` as `pivot_user_id`, `laravel_role_users`.`role_id` as `pivot_role_id`
from `laravel_roles` inner join `laravel_role_users` on `laravel_roles`.`id` = `laravel_role_users`.`role_id`
where `laravel_role_users`.`user_id` = 19

3、获取权限列表中某一个数据,和一对多操作方法一样,但注意返回的表名称;

//注意,多对多这里role()返回的是role_user 表
//可以通过dd($roles)查看,所以,where 需要用role_id 来指明
$roles = User::find(19)->role()->where('role_id', 1)->get();
return $roles;//当然,你也可以使用集合的方式去实现筛选
$roles = User::find(19)->role;
return $roles->where('id', 1);

执行结果:

[{"id": 1,"type": "超级管理员","pivot": {"user_id": 19,"role_id": 1}}
]

执行的SQL为:

select * from `laravel_users` where `laravel_users`.`id` = 19 limit 1select `laravel_roles`.*, `laravel_role_users`.`user_id` as `pivot_user_id`, `laravel_role_users`.`role_id` as `pivot_role_id`
from `laravel_roles` inner join `laravel_role_users` on `laravel_roles`.`id` = `laravel_role_users`.`role_id`
where `laravel_role_users`.`user_id` = 19 and `role_id` = 1

4、反向关联:多对多的反向关联和其它两种方式也差不多,在模型Role.php中:

//反向多对多关联,后面id 是反的
public function user()
{return $this->belongsToMany(User::class, 'role_users', 'role_id' , 'user_id');
}

然后在控制类中执行:

$users = Role::find(1)->user;
return $users;

执行结果如下,即查询拥有权限1(超级管理员)的用户:

[{"id": 24,"username": "小明","password": "123",......"pivot": {"role_id": 1,"user_id": 24}},{"id": 19,"username": "蜡笔小新","password": "123",......"pivot": {"role_id": 1,"user_id": 19}},{"id": 99,"username": "辉夜","password": "123",......"pivot": {"role_id": 1,"user_id": 99}}
]

执行的SQL为:

select * from `laravel_roles` where `laravel_roles`.`id` = 1 limit 1select `laravel_users`.*, `laravel_role_users`.`role_id` as `pivot_role_id`, `laravel_role_users`.`user_id` as `pivot_user_id`
from `laravel_users` inner join `laravel_role_users` on `laravel_users`.`id` = `laravel_role_users`.`user_id`
where `laravel_role_users`.`role_id` = 1

5、多对多会生成一个中间字段:pivot,里面包含多对多的双id

如果想要pivot 字段包含更多的中间表字段,可以自行添加,还可以修改字段名。

比如正向关联中,修改为:

//多对多关联
public function role()
{//参数1:同上//参数2:中间表名//参数3,4 如果是默认值,则可不传return $this->belongsToMany(Role::class, 'role_users', 'user_id', 'role_id')->withPivot('details', 'id')->as('pivot_name');
}

然后执行:

$roles = User::find(19)->role()->where('role_id', 1)->get();
return $roles;

执行结果为:

[{"id": 1,"type": "超级管理员","pivot_name": {"user_id": 19,"role_id": 1,"details": "啦","id": 8}}
]

执行的SQL为:

select * from `laravel_users` where `laravel_users`.`id` = 19 limit 1select `laravel_roles`.*, `laravel_role_users`.`user_id` as `pivot_user_id`, `laravel_role_users`.`role_id` as `pivot_role_id`, `laravel_role_users`.`details` as `pivot_details`, `laravel_role_users`.`id` as `pivot_id`
from `laravel_roles` inner join `laravel_role_users` on `laravel_roles`.`id` = `laravel_role_users`.`role_id`
where `laravel_role_users`.`user_id` = 19 and `role_id` = 1

6、定义多对多绑定时,可以在绑定方法内筛选数据;

比如正向关联中,修改为:

//多对多关联
public function role()
{//参数1:同上//参数2:中间表名//参数3,4 如果是默认值,则可不传return $this->belongsToMany(Role::class, 'role_users', 'user_id', 'role_id')->wherePivot('id', 1);
}

还有wherePivotIn,以及派生的四种方法。

然后执行:

$roles = User::find(19)->role;
return $roles;

输出结果为:

[{"id": 2,"type": "评论审核专员","pivot": {"user_id": 19,"role_id": 2}}
]

执行的SQL为:

select * from `laravel_users` where `laravel_users`.`id` = 19 limit 1select `laravel_roles`.*, `laravel_role_users`.`user_id` as `pivot_user_id`, `laravel_role_users`.`role_id` as `pivot_role_id`
from `laravel_roles` inner join `laravel_role_users` on `laravel_roles`.`id` = `laravel_role_users`.`role_id`
where `laravel_role_users`.`user_id` = 19 and `laravel_role_users`.`id` = 1

除了一对一,一对多,多对多,还有派生的远程一对一,远程一对多,以及多态一对一,多态一对多,多态多对多。

10.5 关联查询

前文讲述了三种常用的关联查询。本节讲述几种常用查询方案。

1、下面两种查询方式是一样的:

//下面两种查询是一样的;
$books = User::find(19)->book;
$books = User::find(19)->book()->get();

2、可以采用where 筛选或闭包。

如:

books = User::find(19)->book()->where('id', 1)->orWhere('id', 11)->get();//或者,执行结果相同
$books = User::find(19)->book()->where(function ($query) {$query->where('id', 1)->orWhere('id', 11);
})->get();

执行结果:

[{"id": 1,"user_id": 19,"title": "《莎士比亚》"},{"id": 11,"user_id": 19,"title": "《完美人生》"}
]

执行的SQL为:

select * from `laravel_users` where `laravel_users`.`id` = 19 limit 1select * from `laravel_books` where `laravel_books`.`user_id` = 19 and `laravel_books`.`user_id` is not null and `id` = 1 or `id` = 11

3、使用has()方法,可以查询某些条件下的关联查询数据。如:

//示例1:获取存在关联书籍的用户列表(言下之意:至少一本书)
$users = User::has('book')->get();
return $users;//示例2:获取存在关联书籍(并超过3 条)的用户列表
$users = User::has('book','>=', 3)->get();
return $users;

执行的SQL分别为:

/*示例1:*/
select * from `laravel_users`
where exists (select * from `laravel_books` where `laravel_users`.`id` = `laravel_books`.`user_id`)/*示例2:*/
select * from `laravel_users`
where (select count(*) from `laravel_books` where `laravel_users`.`id` = `laravel_books`.`user_id`) >= 3

执行结果分别为:

//示例1结果:
[{"id": 19,"username": "蜡笔小新","password": "123",......},{"id": 20,"username": "路飞","password": "123",......},{"id": 21,"username": "黑崎一护","password": "456",......},{"id": 24,"username": "小明","password": "123",......},{"id": 25,"username": "孙悟饭","password": "123",......},......
]//示例2结果:
[{"id": 19,"username": "蜡笔小新","password": "123",......}
]

4、使用whereHas()方法,创建闭包查询;

//whereHas 闭包用法,返回user 表数据
$users = User::whereHas('book', function ($query) {//这里$query 是book 表,通过 book表的 id 查询$query->where('id', 2);
})->get();
//可以理解为查询写书id=2的人是谁。
return $users;

执行的SQL为:

select * from `laravel_users`
where exists (select * from `laravel_books` where `laravel_users`.`id` = `laravel_books`.`user_id` and `id` = 2)

5、使用doesntHave()方法,即has()的反向操作:

//获取不存在关联书籍的用户列表,闭包用法:whereDoesntHave()
$users = User::doesntHave('book')->get();
return $users;

执行的SQL为:

select * from `laravel_users` where not exists (select * from `laravel_books` where `laravel_users`.`id` = `laravel_books`.`user_id`)

6、使用withCount()方法,可以进行关联统计;

如:

//关联统计,会自动给一个book_count 字段
//统计每个用户有多少本书
$users = User::withCount('book')->get();
return $users;

执行的SQL为:

select
`laravel_users`.*,
(select count(*) from `laravel_books` where `laravel_users`.`id` = `laravel_books`.`user_id`) as `book_count`
from `laravel_users`

再如:

//给多个关系添加统计:profile_count,book_count
$users = User::withCount(['profile', 'book'])->get();
return $users;

执行的SQL为:

select
`laravel_users`.*,
(select count(*) from `laravel_profiles` where `laravel_users`.`id` = `laravel_profiles`.`user_id`) as `profile_count`,
(select count(*) from `laravel_books` where `laravel_users`.`id` = `laravel_books`.`user_id`) as `book_count`
from `laravel_users`

再如:

//关联统计再结合闭包进行筛选,还可以设置别名
$users = User::withCount(['profile', 'book' => function ($query) {//这里限制被统计的记录,即只查询表book中user_id=19的数据和$query->where('user_id', 19);
}])->get();
return $users;

执行的SQL为:

select
`laravel_users`.*,
(select count(*) from `laravel_profiles` where `laravel_users`.`id` = `laravel_profiles`.`user_id`) as `profile_count`,
(select count(*) from `laravel_books` where `laravel_users`.`id` = `laravel_books`.`user_id` and `user_id` = 19) as `book_count`
from `laravel_users`

以上。

【Laravel笔记】10. 模型的关联查询相关推荐

  1. Django框架(14.Django中模型类的关系,以及模型类关联查询)

    Django中模型类的关系,以及模型类关联查询 1.模型类关系 1.1 一对多关系 1.2多对多关系 1.3 一对一关系 1.4 一对多举例: 1.5 多对多举例: 1.6 一对一举例: 2.关联查询 ...

  2. 二十八、PHP框架Laravel学习笔记——模型的关联查询

    二.关联查询 前几篇博文,了解了三种基础的关联模型,并简单的进行查询: 本节课,我们详细的了解更多的查询方案: //下面两种查询是一样的: $books = User::find(19)->bo ...

  3. php join查询,thinkphp5模型join关联查询

    class Space extends Model { public function meetingroom() { return $this->hasMany('meetingroom',' ...

  4. Django学习笔记(3):使用模型类进行查询(查询函数、F对象、Q对象、聚合函数、查询集、模型类关系、关联查询、自关联、管理器)

    文章目录 1.查询函数 2.F对象 3.Q对象 4.聚合函数 5.Count函数 6.查询集 查询集的特性 对查询集进行切片 判断一个查询集中是否有数据 7.模型类之间的关系 一对多关系 多对多关系 ...

  5. NHibernate之旅(10):探索父子(一对多)关联查询

    本节内容 关联查询引入 一对多关联查询 1.原生SQL关联查询 2.HQL关联查询 3.Criteria API关联查询 结语 关联查询引入 在NHibernate中提供了三种查询方式给我们选择:NH ...

  6. mysql中的自关联详解_Laravel - MySQL数据库的使用详解6(Eloquent ORM用法3:模型关联、关联查询)...

    一.一对一关联 一对一关联是很基本的关联.假设一个 User 对应到一个 Phone,phones 表结构如下(通过 user_id 关联 user 表的主键): 1,定义一对一关联 (1)User ...

  7. php ci model条件查询,Laravel关系模型指定条件查询方法

    对于关系模型来说,有时候我们需要甄别关联后结果,例如,班级和学生是一对多关联,我现在查询班级,但是想只显示正常状态,即状态为1的学生,因为有的学生从这个班级里面删除了,状态是4,那么我们在查询的时候就 ...

  8. 【Laravel笔记】12. 模型的预加载

    关于 拾年之璐 微信公众号:知行校园汇,点击查看,欢迎关注 其他平台(点击蓝字可访问): GitHub | Gitee | 哔哩哔哩 | 语雀 | 简书 | 微信小程序 | 知行达摩院 本文专栏:La ...

  9. thinkPHP6.0入门笔记(七)——关联模型

    thinPHP6.0的关联模型及关联方法 1.一对一关联 1.1一对一关联查询 1.2一对一关联新增 1.3一对一关联删除 1.4一对一关联修改 2.一对多关联 2.1一对多关联模型常用方法 3.多对 ...

最新文章

  1. Python3 的urllib实例
  2. 万能 Transformer,你应该知道的一切
  3. Weblogic 前端热部署
  4. Android Studio出现Unable to start the daemon process问题
  5. kali Linux 安装
  6. 某个JAVA类断点无效_解决eclipse中断点调试不起作用的问题
  7. 被低估的“败家爷们”
  8. 菜鸟编译OPenJDK全过程记录
  9. Linux用户基础操作入门
  10. Python是最好的编程语言,Locust是最好的压测工具,不服来辩!
  11. Redis 查看key的有效时间
  12. wps android版本下载,wps文档app下载-wps文档 安卓版v2.7.6-PC6安卓网
  13. 光电信息科学与工程学c语言吗,光电信息科学与工程是热门吗?本文讲给你讲个透彻...
  14. 微信公众号模板消息配置和发送
  15. 三星s6如何打开位置服务器,三星S6开发者选项在哪里?怎么打开
  16. 量化评价和质化评价举例_数据质量量化评价研究与实现
  17. pytorch —— 正则化之weight_decay
  18. 经典查找算法 --- B+树
  19. 转 给SSD(固态硬盘)编程
  20. 在本地计算机无法启动错误1068,为什么本地计算机“无法启动Print Spooler服务,错误1068,依存服务或组无法启动”?...

热门文章

  1. 网络代理和网络转发的区别
  2. 入手Invicta 8926 OB潜水自动机械腕表
  3. 解决使用layui上传文件时提示“请求上传接口出现异常”
  4. 迟到的2018年终总结
  5. uni-app 手势放大图片
  6. 东方式插花注重花材所表达的内容美
  7. Fastdfs数据迁移方案
  8. emacs 使用汇总
  9. The ninth day_打飞机项目
  10. appium第一个脚本