关于 拾年之璐

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

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

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. usaco Job Processing(mark)
  2. 从零入门 Serverless | 一文详解 Serverless 架构模式
  3. Android SQLite (三 ) 全面详解(一)
  4. socket多线程方式案例
  5. java jsf_将Java 8日期时间API与JSF和Java EE 7结合使用
  6. 免费Linux系统和生信宝典原创学习教程
  7. 生成javaDoc文档MyEclipse 0914
  8. 关于Python中的错误与异常,你是否了解的够仔细?
  9. WordPress 插件漏洞被利用,近 20 万站点还没打补丁
  10. MPAndroidChart 2.15使用记录
  11. react-native 自定义view向js暴露接口方法
  12. 3.Event Loop
  13. DependsOn注解
  14. 各省简称 拼音 缩写_中国省市县地区首字母缩写
  15. 网页内容监控 - 怎么才能做到网站内容实时推送百度?
  16. android12.0(S) 通知栏不显示闹钟和静音图标 bug
  17. 计算机/电脑为什么拥有计算能力
  18. 重装 Mac 系统后的安装软件和个人配置[个人习惯]
  19. word模板填充数据
  20. Python字符串格式化 (%占位操作符)

热门文章

  1. web前端年会抽奖工具
  2. 不算不知道,花呗分期的真实利率居然这么高
  3. 虾皮系统老出现服务器错误,Shopee卖家须知:虾皮系统什么状况会自动取消订单?...
  4. 51单片机数码管滚动显示学号_静、动态数码管动态显示
  5. 【工业4.0系列谈之五】建设智能工厂 可从这6个方面着手
  6. 【智能制造】博创智能注塑生产智能化应用之路
  7. 聊聊Elasticsearch的NodesSniffer
  8. 计算机网络部分知识梳理
  9. 互联网寒冬——“大裁员”
  10. 人工智能领域数据标注行业的核心需求痛点