1. 为何要使用 Query Builder
Query builder 的最大好处就是,对于 SQL 的 select from where join group by order by limit offset having on 等关键字都转换为了类的方法,简化了 SQL 的使用成本,大大简化了代码量,原先一些操作数据库相关的一次性的 servicelogic 相关的函数,可以替换为直接 Builder 操作数据库。
Laravel 中关键字都实现在了下面两个类中:
\Illuminate\Database\Query\Builder
\Illuminate\Database\Query\JoinClause
2. 创建库 & Model
接着上篇文章对评论系统设计的一点总结,总结一下 Laravel Eloquent Builder 的一些用法。
首先用下面的 MySQL 语句创建存储评论的数据库表,并生成 Laravel 对应的 Model,用于检索数据库中的数据。
1CREATE TABLE `Comment` (
2 `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键,评论id',
3 `replied_id` int(11) NOT NULL DEFAULT '0' COMMENT '被评论id',
4 `replied_root_id` int(11) NOT NULL DEFAULT '0' COMMENT '直接评论id',
5 `content` text COMMENT '评论内容',
6 `status` int(11) DEFAULT NULL '评论状态',
7 `from_user_id` int(11) NOT NULL DEFAULT '0' COMMENT '评论人id',
8 `from_user_name` varchar(20) NOT NULL DEFAULT '' COMMENT '评论人姓名',
9 `to_user_id` int(11) DEFAULT '0' COMMENT '被评论人id',
10 `to_user_name` varchar(20) NOT NULL DEFAULT '' COMMENT '被评论人姓名',
11 `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP '创建时间',
12 PRIMARY KEY (`id`)
13) ENGINE=InnoDB DEFAULT CHARSET=utf8
1<?php
2/**
3 * Created by PhpStorm.
4 * User: yangzhen
5 * Date: 2018/4/3
6 * Time: 20:26
7 */
8
9namespace App\Model;
10
11
12use Illuminate\Database\Eloquent\Model;
13
14/**
15 * App\Model\Comment
16 *
17 * @property int $id 主键,评论id
18 * @property int $replied_id 被评论id
19 * @property int $replied_root_id 直接评论id
20 * @property string|null $content 评论内容
21 * @property int|null $status
22 * @property int $from_user_id 评论人id
23 * @property string $from_user_name 评论人姓名
24 * @property int|null $to_user_id 被评论人id
25 * @property string $to_user_name 被评论人姓名
26 * @property string $create_at
27 * @method static \Illuminate\Database\Eloquent\Builder|\App\Model\Comment whereContent($value)
28 * @method static \Illuminate\Database\Eloquent\Builder|\App\Model\Comment whereCreateAt($value)
29 * @method static \Illuminate\Database\Eloquent\Builder|\App\Model\Comment whereFromUserId($value)
30 * @method static \Illuminate\Database\Eloquent\Builder|\App\Model\Comment whereFromUserName($value)
31 * @method static \Illuminate\Database\Eloquent\Builder|\App\Model\Comment whereId($value)
32 * @method static \Illuminate\Database\Eloquent\Builder|\App\Model\Comment whereRepliedId($value)
33 * @method static \Illuminate\Database\Eloquent\Builder|\App\Model\Comment whereRepliedRootId($value)
34 * @method static \Illuminate\Database\Eloquent\Builder|\App\Model\Comment whereStatus($value)
35 * @method static \Illuminate\Database\Eloquent\Builder|\App\Model\Comment whereToUserId($value)
36 * @method static \Illuminate\Database\Eloquent\Builder|\App\Model\Comment whereToUserName($value)
37 */
38class Comment extends Model
39{
40 protected $table = 'Comment';
41 protected $primaryKey = 'id';
42 public $timestamps = false;
43
44}
3. 使用案例
好,现在假想下面一个场景:
查询直接评论 id 分别为 10,11,12 的最近 7 天、评论内容含有关键字知识、发表评论用户名为 soull11201 或被评论用户名为 soul11201、按照创建时间倒排后的前 10 条数据,并分别计算每个直接评论下面一共含有多少条数据。
粗暴的构造 sql 如下:。
1-- 10
2select * from Comment
3where
4 content = '知识'
5 and (from_user_name = 'soul11201' or to_user_name = 'soul11201')
6 and replied_root_id = 10
7 order by create_at desc
8 limit 10;
9
10select count(1) replied_root_id10_total_num from Comment
11where
12 content = '知识'
13 and (from_user_name = 'soul11201' or to_user_name = 'soul11201')
14 and replied_root_id = 10
15
16-- 11
17select * from Comment
18where
19 content = '知识'
20 and (from_user_name = 'soul11201' or to_user_name = 'soul11201')
21 and replied_root_id = 11
22 order by create_at desc
23 limit 10;
24
25select count(1) replied_root_id10_total_num from Comment
26where
27 content = '知识'
28 and (from_user_name = 'soul11201' or to_user_name = 'soul11201')
29 and replied_root_id = 11
30
31-- 12
32select * from Comment
33where
34 content = '知识'
35 and (from_user_name = 'soul11201' or to_user_name = 'soul11201')
36 and replied_root_id = 12
37 order by create_at desc
38 limit 10;
39
40select count(1) replied_root_id10_total_num from Comment
41where
42 content = '知识'
43 and (from_user_name = 'soul11201' or to_user_name = 'soul11201')
44 and replied_root_id = 12
根据上面的 sql 构造,转换成如下的 Eloquent Builder 使用的代码:
1<?php
2/**
3 * Created by PhpStorm.
4 * User: yangzhen
5 * Date: 2018/4/3
6 * Time: 20:46
7 */
8
9
10$replied_root_ids = [10, 11, 12];
11
12//获取一个 \Illuminate\Database\Eloquent\Builder 实例
13$query = \App\Model\Comment::query();
14
15$query->where('content','知识')
16 ->where(function (\Illuminate\Database\Eloquent\Builder $builder){
17 //$builder 这是一个新的 builder 作为 $query 一个嵌入的查询 builder ,否则的话orWhere 根本无法实现(因为or的优先级问题),
18 $builder->where('from_user_name', 'soul11201');
19 $builder->orWhere('to_user_name', 'soul11201');
20 });
21
22
23$coments = [];
24$total_num = [];
25
26foreach ($replied_root_ids as $replied_root_id) {
27
28 $new_query = \App\Model\Comment::whereRepliedRootId($replied_root_id)
29 ->addNestedWhereQuery($query);
30
31 //此处先用来查询总条数
32 $total_num[$replied_root_id] = $new_query->count();
33 //然后用来查询10条信息,顺序反之不可。
34 $coments[$replied_root_id] = $new_query->orderBy('create_at', 'desc')
35 ->limit(10)
36 ->get()
37 ->all();
38}
4. 执行流程分析
\Illuminate\Database\Eloquent\Builder::where()
1 /**
2 * Add a basic where clause to the query.
3 *
4 * @param string|array|\Closure $column
5 * @param string $operator
6 * @param mixed $value
7 * @param string $boolean
8 * @return $this
9 */
10 public function where($column, $operator = null, $value = null, $boolean = 'and')
11 {
12 if ($column instanceof Closure) {
13 // 返回一个新的 Eloquent Builder
14 $query = $this->model->newQueryWithoutScopes();
15 //匿名函数调用,
16 //当 where 条件有复杂的条件表达式的时候
17 //比如解决上面 表达式中 (from_user_name = 'soul11201' or to_user_name = 'soul11201') or 优先级的问题
18 //直接使用 where() 无法解决,只能使用一个新的Builder来嵌入到原先的Builder中
19 $column($query);
20 //$this->query 是类 \Illuminate\Database\Query\Builder 的实例
21 //将新的 Eloquent builder 的 Query\Builder 最为一个整体嵌入到原先Eloquent Builder的 `Query\Builder`的where表达式中,
22 //就可以解决上面 or 优先级的问题
23 $this->query->addNestedWhereQuery($query->getQuery(), $boolean);
24 } else {
25 $this->query->where(...func_get_args());
26 }
27
28 return $this;
29 }
mixin
因为 \Illuminate\Database\Eloquent\Builder mixin 类\Illuminate\Database\Query
\Illuminate\Database\Eloquent\Builder::count()
\Illuminate\Database\Eloquent\Builder::orderby()
\Illuminate\Database\Eloquent\Builder::limit()
都是利用魔术方法__call 间接使用的\Illuminate\Database\Query 的方法
1 /**
2 * The base query builder instance.
3 *
4 * @var \Illuminate\Database\Query\Builder
5 */
6 protected $query;
7
8 ...
9 此处省略
10 ...
11
12 public function __call($method, $parameters)
13 {
14 ...
15 此处省略
16 ...
17 $this->query->{$method}(...$parameters);
18
19 return $this;
20 }
\Illuminate\Database\Eloquent\Builder::get()
\Illuminate\Database\Eloquent\Builder 是 \Illuminate\Database\Eloquent\Mdel 子类 与\Illuminate\Database\Query\Builder 沟通的桥梁。其中一个作用就是对\Illuminate\Database\Query\Builder 查询的数组结果(由\Illuminate\Support\Collection 进行包裹)渲染成\Illuminate\Database\Eloquent\Model 子类的对象数组结果(由\Illuminate\Database\Eloquent\Collection 进行包裹)。
1 /**
2 * Execute the query as a "select" statement.
3 *
4 * @param array $columns
5 * @return \Illuminate\Database\Eloquent\Collection|static[]
6 */
7 public function get($columns = ['*'])
8 {
9 //应用其他注入构造条件
10 $builder = $this->applyScopes();
11
12 // If we actually found models we will also eager load any relationships that
13 // have been specified as needing to be eager loaded, which will solve the
14 // n+1 query issue for the developers to avoid running a lot of queries.
15 if (count($models = $builder->getModels($columns)) > 0) {
16 $models = $builder->eagerLoadRelations($models);
17 }
18
19 return $builder->getModel()->newCollection($models);
20 }
21
22 /**
23 * Get the hydrated models without eager loading.
24 *
25 * @param array $columns
26 * @return \Illuminate\Database\Eloquent\Model[]
27 */
28 public function getModels($columns = ['*'])
29 {
30 return $this->model->hydrate(
31 $this->query->get($columns)->all()
32 )->all();
33 }
Illuminate\Support\Collection::all()
\Illuminate\Database\Eloquent\Collection 是 Illuminate\Support\Collection 的子类,all()方法指向的是同一个方法,直接返回其所包裹的数组。
作者介绍:
杨振振,技术保障部,17 年 8 月加入链家。先后参与过热链计划、移动审批、圣诞大屏、邮箱代理等项目。
本文转载自公众号贝壳产品技术(ID:gh_9afeb423f390)。
原文链接:
https://mp.weixin.qq.com/s/3ANed5AO1gf4se8g-rrysw
更多内容推荐
数据库每日一题 --- 第 6 天:删除重复的电子邮箱
表: Person
2022-06-08
22|数据库应用(二):数据库 ORM 对象关系映射
这节课,我们继续深入学习数据库应用,熟悉SQL语言应用,并实现数据库与项目的联动。
2023-06-12
星环科技打造自主可控的高性能数据库,开启国产化升级新篇章
星环科技自成立以来,一直致力于国产化数据库的自主研发,打造了自主可控的高性能分布式分析型数据库ArgoDB和分布式交易型数据库KunDB。交易型数据库KunDB具备较强的SQL兼容性,同时具备高可用、高并发、在线扩缩容、数据强一致性等能力,适用于操作型业务、
2022-05-10
13|JDBC 访问框架:如何抽取 JDBC 模板并隔离数据库?
数据访问的特性
2023-04-10
C# 窗体应用 DataGridView,使用数据库(Sql 和 MySQl)对 DataGridView 绑定数据源,获取数据
前面我们用了,类库对象进行数据绑定,不懂的童鞋可以去找博主上一篇文章,今天给大家演示使用数据库对datadridview进行数据绑定,其实也很简单啦,让我们卷起来。
2022-07-22
如何化解 35 岁危机?华为云数据库首席架构师 20 年技术经验分享
面对所谓的35岁危机,冯柯强调最重要的是要有积累和分析沉淀。
2022-06-24
数据库每日一题 --- 第 2 天:查找重复的电子邮箱
编写一个 SQL 查询,查找 Person 表中所有重复的电子邮箱。
2022-06-04
15|mBatis:如何将 SQL 语句配置化?
mBatis:如何将SQL语句配置化?
2023-04-14
老大让我优化数据库,我上来就分库分表,他过来就是一 jio
一、朴实无华的 - 分表
2021-10-30
关于 LLM 和图数据库、知识图谱的那些事
本文着重介绍了 LLM、RAG、Graph 是什么,以及 LLM 如何同知识图谱结合,让知识抽取更加便利。此外,还讲述了一些 LLM 在数据库领域的应用场景,比如:用自然语言查询数据。
2023-08-16
数字经济时代的开源数据库创新 | 2022 开放原子全球开源峰会数据库分论坛圆满召开
7 月 27 日,2022 开放原子全球开源峰会数据库分论坛在北京成功举办。论坛以 “数字经济时代的开源数据库创新” 为主题,围绕数据库前沿技术、数据库开源生态建设、数据库应用实践等方面开展技术交流和经验分享,促进数字经济产业快速发展。
2022-07-28
ODC 3.4.0 现已上线,让数据库开发更简单
OceanBase 开发者工具(OceanBase Developer Center,ODC)作为 OceanBase 数据库量身打造的企业级数据库开发平台,旨在帮助企业安全、高效地使用数据库。用户可通过 ODC 创建和管理数据库中的表、视图等 10 余种数据库对象。基于 WebSQL,ODC 提供了 SQL 窗
2022-09-16
12|让 AI 帮你写个小插件,轻松处理 Excel 文件
让AI帮你写个小插件,轻松处理Excel文件
2023-04-07
数智平台多维数据库:新时代的数据管理利器
多维数据库其实是用来满足企业的管理需要,其需求是由战略层到执行层自上而下产生的。而且,精细化管理程度越高的企业,对于多维数据库的需求越强烈;同时,也对复合型人才的要求越高,既要懂业务又要懂IT,以此来充分发挥数据的价值。
2023-06-15
17|框架升级:如何小步安全地升级数据库框架?
今天我们以Sharing项目为例,一起把项目中原先采用SQL拼写的方式替换为使用Room框架来统一管理缓存数据。
2023-03-20
数据库人才招聘 | 海量数据
海量数据招聘
2022-03-18
flutter 系列之:flutter 中的 builder
flutter中有很多种Builder,虽然所有的builder都是构造器,但是不同的builder之间还是有很多差距的。今天我们来详细介绍一下Builder,LayoutBuilder,StatefulBuilder这几个builder的使用。
2022-06-20
加餐|GPT 编程(上) :如何用 ChatGPT 辅助我们编程?
如何用ChatGPT辅助我们编程?
2023-05-15
10 个人 9 个答错,另外 1 个只对一半:数据库的锁
========
2021-10-31
精彩回顾|【ACDU 中国行·杭州站】数据库主题交流活动成功举办!
8月19日下午,【ACDU 中国行·杭州站】在杭州西溪万怡酒店圆满落下帷幕。六位数据库行业领军人物聚焦数据库技术的核心要素、数据库降本增效、智能运维等热门话题展开了精彩的分享。
2023-08-23
推荐阅读
15|检索增强生成:通过 RAG 助力鲜花运营
2023-10-11
MySQL 索引入门
2023-11-16
16|连接数据库:通过链和代理查询鲜花信息
2023-10-13
04-volatile 关键字简介
2023-09-26
RazorSQL for Mac(多功能 SQL 数据库管理器) 支持 M1/M2 v10.5.0 注册激活版
2023-12-01
亚马逊 MemoryDB 快速向量搜索功能全面可用
强大的轻级思维导图软件 iMap Builder 中文最新版
2023-11-28
电子书
大厂实战PPT下载
换一换 李飞 博士 | 数势科技 算法专家
杨维亮 | 滴普科技 FastData产品线 DLink SE
梁玉 (琰玉) | 阿里巴巴 前端技术专家
评论