【Laravel笔记】10. 模型的关联查询
关于 拾年之璐
微信公众号:知行校园汇,点击查看,欢迎关注
其他平台(点击蓝字可访问):
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.php
和Profile.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. 模型的关联查询相关推荐
- Django框架(14.Django中模型类的关系,以及模型类关联查询)
Django中模型类的关系,以及模型类关联查询 1.模型类关系 1.1 一对多关系 1.2多对多关系 1.3 一对一关系 1.4 一对多举例: 1.5 多对多举例: 1.6 一对一举例: 2.关联查询 ...
- 二十八、PHP框架Laravel学习笔记——模型的关联查询
二.关联查询 前几篇博文,了解了三种基础的关联模型,并简单的进行查询: 本节课,我们详细的了解更多的查询方案: //下面两种查询是一样的: $books = User::find(19)->bo ...
- php join查询,thinkphp5模型join关联查询
class Space extends Model { public function meetingroom() { return $this->hasMany('meetingroom',' ...
- Django学习笔记(3):使用模型类进行查询(查询函数、F对象、Q对象、聚合函数、查询集、模型类关系、关联查询、自关联、管理器)
文章目录 1.查询函数 2.F对象 3.Q对象 4.聚合函数 5.Count函数 6.查询集 查询集的特性 对查询集进行切片 判断一个查询集中是否有数据 7.模型类之间的关系 一对多关系 多对多关系 ...
- NHibernate之旅(10):探索父子(一对多)关联查询
本节内容 关联查询引入 一对多关联查询 1.原生SQL关联查询 2.HQL关联查询 3.Criteria API关联查询 结语 关联查询引入 在NHibernate中提供了三种查询方式给我们选择:NH ...
- mysql中的自关联详解_Laravel - MySQL数据库的使用详解6(Eloquent ORM用法3:模型关联、关联查询)...
一.一对一关联 一对一关联是很基本的关联.假设一个 User 对应到一个 Phone,phones 表结构如下(通过 user_id 关联 user 表的主键): 1,定义一对一关联 (1)User ...
- php ci model条件查询,Laravel关系模型指定条件查询方法
对于关系模型来说,有时候我们需要甄别关联后结果,例如,班级和学生是一对多关联,我现在查询班级,但是想只显示正常状态,即状态为1的学生,因为有的学生从这个班级里面删除了,状态是4,那么我们在查询的时候就 ...
- 【Laravel笔记】12. 模型的预加载
关于 拾年之璐 微信公众号:知行校园汇,点击查看,欢迎关注 其他平台(点击蓝字可访问): GitHub | Gitee | 哔哩哔哩 | 语雀 | 简书 | 微信小程序 | 知行达摩院 本文专栏:La ...
- thinkPHP6.0入门笔记(七)——关联模型
thinPHP6.0的关联模型及关联方法 1.一对一关联 1.1一对一关联查询 1.2一对一关联新增 1.3一对一关联删除 1.4一对一关联修改 2.一对多关联 2.1一对多关联模型常用方法 3.多对 ...
最新文章
- usaco Job Processing(mark)
- 从零入门 Serverless | 一文详解 Serverless 架构模式
- Android SQLite (三 ) 全面详解(一)
- socket多线程方式案例
- java jsf_将Java 8日期时间API与JSF和Java EE 7结合使用
- 免费Linux系统和生信宝典原创学习教程
- 生成javaDoc文档MyEclipse 0914
- 关于Python中的错误与异常,你是否了解的够仔细?
- WordPress 插件漏洞被利用,近 20 万站点还没打补丁
- MPAndroidChart 2.15使用记录
- react-native 自定义view向js暴露接口方法
- 3.Event Loop
- DependsOn注解
- 各省简称 拼音 缩写_中国省市县地区首字母缩写
- 网页内容监控 - 怎么才能做到网站内容实时推送百度?
- android12.0(S) 通知栏不显示闹钟和静音图标 bug
- 计算机/电脑为什么拥有计算能力
- 重装 Mac 系统后的安装软件和个人配置[个人习惯]
- word模板填充数据
- Python字符串格式化 (%占位操作符)