lumen model orm
此方法 可以执行任何 原生sql语句.
DB::statement($sql);
我尽量遍历写一遍Illuminate\Database\Query\Builder类的大部分方法
select
设置查询字段
1 2 | Notice::select( 'title' )->get(); Notice::select([ 'title' , 'content' ])->get(); |
selectRaw
查询自定义内容
1 | Notice::selectRaw( "count('id') as notice_count" )->get(); |
addSelect
如果您已经有一个查询构建器实例,并且希望在其现有select子句中添加一列,则可以使用以下addSelect
方法:
1 2 3 | $query = DB::table( 'users' )-> select ( 'name' ); $users = $query->addSelect( 'age' )-> get (); |
distinct
该distinct
方法允许您强制查询返回不同的结果:
1 | $users = DB::table( 'users' )->distinct()-> get (); |
from
设置表名属性,table()方法也是通过这个方法设置
1 2 3 4 5 6 7 | DB::table( 'users' ) ->whereExists(function ($query) { $query-> select (DB::raw(1)) -> from ( 'orders' ) ->whereRaw( 'orders.user_id = users.id' ); }) -> get (); |
上面的查询其实就是with()方法的原理了,转成sql如下
1 2 3 4 | select * from users where exists ( select 1 from orders where orders.user_id = users.id ) |
这里补充一下模型关联的方法
hasOne
1 2 3 4 | public function user($ class = User:: class ) { return $ this ->hasOne($ class , 'id' , 'user_id' ); } |
order表的user_id关联user表的id,一对一,$class 可以作为参数,当user子类model关联order子类model的时候,可以灵活重写
1 2 3 4 | public function user($ class = User:: class ) { return $ this ->hasOne($ class , 'id' , 'user_id' ); } |
当你需要关联最后一条记录时
1 2 3 4 | public function order($ class = Order:: class ) { return $ this ->hasOne($ class , 'user_id' , 'id' )->orderBy( 'id' , 'desc' ); } |
where之类的条件拼接也是可行的
1 2 3 4 | public function order($ class = Order:: class ) { return $ this ->hasOne($ class , 'user_id' , 'id' )-> where ( 'status' , Order::STATUS_CREATE); } |
hasMany
1 2 3 4 | public function orders($ class = Order:: class ) { return $ this ->hasMany($ class , 'user_id' , 'id' ); } |
user表的id关联order表的user_id,一对多
belongsTo
1 2 3 4 | public function user($ class = User:: class ) { return $ this ->belongsTo($ class , 'user_id' , 'id' ); } |
order表的user_id关联user表的id,一对一
这里有人可能会问,这belongsTo和hasOne有啥区别
网上是这样解释的
hasOne(hasMany)使用在:外键在子关联对象中,如业务上user表在order表之上,在User模型使用hasOne关联order
1 2 3 4 5 6 | class User{ public function order($ class = Order:: class ) { return $ this ->hasOne($ class , 'user_id' , 'id' ); } } |
belongsTo(belongsToMany)使用在:外键在父联对象中,如业务上order表在user表之下,在Order模型使用belongsTo关联user
1 2 3 4 5 6 | class Order{ public function user($ class = User:: class ) { return $ this ->belongsTo($ class , 'user_id' , 'id' ); } } |
1 | belongsToMany |
1 2 3 4 5 6 7 8 9 | public function roles() { return $ this ->belongsToMany( \Common\Models\Rbac\Role:: class , 'admin_has_roles' , 'admin_id' , 'role_id' ); } |
管理员表admin,角色表role,中间表为admin_has_roles,admin表可以通过中间表查出对应的角色集合
我们可以看出,这里的使用也印证了hasMany与belongsToMany的区别,belongsToMany是向上查询的,必有一张admin_has_roles的中间表进行关联
这样描述可能有点抽象,我们可以假设上面的user和order的例子,
当一个order指向多个user时(比如多人拼单,只是假设),我们不可能在user表加order_id,所以下级业务表order在关联上级业务表user时,必会有order_has_users之类的中间表,也会用到belongsToMany关联,而不是hasMany了(暂时没有更通俗的表述,有好的建议可以评论补充一下)
join
关联查询,join()方法最后还有两个参数,$type和$where, $type是链表方式(inner,left,right,cross),$where是关联条件(on,where)
后面的一些join方法(joinWhere,leftJoin,leftJoinWhere,rightJoin,rightJoinWhere,crossJoin)的实现是通过传$type和$where调用join()来实现的
1 2 3 4 5 | $users = DB::table( 'users' ) -> join ( 'contacts' , 'users.id' , '=' , 'contacts.user_id' ) -> join ( 'orders' , 'users.id' , '=' , 'orders.user_id' ) -> select ( 'users.*' , 'contacts.phone' , 'orders.price' ) -> get (); |
cross join(笛卡尔积): mysql的交叉连接,数据分析和统计有时会用得上
cross join相关:https://www.yiibai.com/mysql/cross-join.html
joinWhere
join的时候,$where参数的on值换成了where值, 外键关联换成条件
1 2 3 4 5 | $users = DB::table( 'users' ) ->joinWhere( 'contacts' , 'contacts.type' , '=' , '1' ) -> join ( 'orders' , 'users.id' , '=' , 'orders.user_id' ) -> select ( 'users.*' , 'contacts.phone' , 'orders.price' ) -> get (); |
leftJoin
join的时候,$type参数的inner值换成了left值, 左匹配
1 2 3 | $users = DB::table( 'users' ) ->leftJoin( 'posts' , 'users.id' , '=' , 'posts.user_id' ) -> get (); |
leftJoinWhere
join的时候,
$type参数的inner值换成了left值, 左匹配
$where参数的on值换成了where值, 外键关联换成条件
1 2 3 | $users = DB::table( 'users' ) ->leftJoinWhere( 'posts' , 'posts.type' , '=' , '1' ) -> get (); |
rightJoin
同理
rightJoinWhere
同理
crossJoin
同理
---------后面的暂时不一一写了,先写几个常用的方法----------
where
为了使用方便,where方法提供了多种传值方式, 最后有一个$boolean参数 默认and, 可传or
1 2 3 4 | $user = DB::table( 'users' )-> where ( 'name' , 'John' )->first(); $user = DB::table( 'users' )-> where ( 'name' , '=' , 'John' )->first(); $user = DB::table( 'users' )-> where ([[ 'name' , '=' , 'John' ], [ 'telephone' , '=' , '18812341234' ]])->first(); echo $user->name; |
orWhere
1 2 3 4 | $users = DB::table( 'users' ) -> where ( 'votes' , '>' , 100) ->orWhere( 'name' , 'John' ) -> get (); |
groupBy
可传数组或多个参数
1 2 | Notice::groupBy( 'title' , 'id' )->get(); Notice::groupBy([ 'title' , 'id' ])->get(); |
having
1 | Notice::having( 'title' , '=' , '2' )->get(); |
orHaving
1 | Notice::having( 'title' , '=' , '2' )->orHaving( 'title' , '=' , '1' )->get(); |
havingRaw
1 2 3 4 5 | $orders = DB::table( 'orders' ) ->select( 'department' , DB::raw( 'SUM(price) as total_sales' )) ->groupBy( 'department' ) ->havingRaw( 'SUM(price) > ?' , [2500]) ->get(); |
orHavingRaw
1 2 3 4 5 | $orders = DB::table( 'orders' ) ->select( 'department' , DB::raw( 'SUM(price) as total_sales' )) ->groupBy( 'department' ) ->orHavingRaw( 'SUM(price) > ?' , [2500]) ->get(); |
orderBy
orderBy只能多个拼接
1 2 | Notice::orderBy( 'title' )->get(); Notice::orderBy( 'title' )->orderBy( 'content' )->get(); |
orderByDesc
1 | Notice::orderByDesc( 'title' )->get(); |
latest
1 2 3 4 | public function latest( $column = 'created_at' ) { return $this ->orderBy( $column , 'desc' ); } |
oldest
1 2 3 4 | public function oldest( $column = 'created_at' ) { return $this ->orderBy( $column , 'asc' ); } |
inRandomOrder
随机排序法 可传参,传同样参数会得到同样的排列
1 2 | Notice::inRandomOrder()->get(); Notice::inRandomOrder(1)->get(); |
orderByRaw
1 | Notice::orderByRaw( 'title, content' )->get(); |
find
注:从源码上看find和findMary是通的,find第一个参数传数组时,会调用findMany方法
1 2 3 | Notice::find(1); Notice::find(1, [ 'title' ]); Notice::find([1,2], [ 'title' ]); |
value
从查询的第一个结果中获取单个列的值
1 | Notice:: where ( 'title' , 1)->value( 'title' ); |
get
查询列,可指定查询项get(['title', 'content']),
1 | Notice:: where ( 'title' , 1)-> get (); |
注:该特别注意的是get查询不到结果时返回的是一个空数组,不能直接用!判断
paginate
返回指定查询条数的数据,总条数,当前分页之类的
1 | DB::table( 'notice' )->paginate(); |
simplePaginate 同上 返回参数有所删减,数据量较大的查询性能较高
cursor
数据量大时,用cursor做遍历会节省很多内存
1 2 3 4 5 | DB::table( 'notice' )-> get (); foreach (DB::table( 'notice' )->cursor() as $notice){ var_dump($notice); } |
chunkById
分次查询,第一个参数是每次查的条数,默认根据id查,如果需定制可在第三个参数传
1 2 3 4 5 6 7 | $noticeArr = []; $notice = DB::table( 'notice' )->chunkById(10, function($notices) use (&$noticeArr){ $noticeArr[] = json_decode(json_encode($notices, 256), true ); }, 'notice_id' ); var_dump($notice); var_dump($noticeArr); exit(); |
该方法为分页查询,如果涉及更新,需慎用该方法
pluck
查询某一个字段,返回该只有该字段的数组集合,第二个参数为指定某个参数为键,返回键值对集合
1 2 | DB::table( 'roles' )->pluck( 'title' ); DB::table( 'roles' )->pluck( 'title' , 'name' ); |
implode
根据查询字段和符号分割
1 | DB::table( 'notice' )->implode( 'title' , ',' ); //titlea,title2,titlec |
exists
判断查询记录是否存在
1 2 | DB::table( 'notice' )-> where ( 'status' , 1)->exists(); //true DB::table( 'notice' )-> where ( 'status' , 'a' )->exists(); //false |
doesntExist
同exists,返回结果和exists相反
1 2 | DB::table( 'notice' )-> where ( 'status' , 1)->exists(); //false DB::table( 'notice' )-> where ( 'status' , 'a' )->exists(); //true |
count
返回个数
1 | DB::table( 'notice' )-> where ( 'status' , 1)->count(); |
min
最小
1 | DB::table( 'notice' )->min( 'notice_id' ); |
max
最大
1 | DB::table( 'notice' )->max( 'notice_id' ); |
sum
总和
1 | DB::table( 'notice' )->sum( 'notice_id' ); |
avg
平均
1 | DB::table( 'notice' )->avg( 'notice_id' ); |
average 同avg
1 | aggregate<br>查询生成器还提供了各种聚合方法,如计数、max、min、avg和和。您可以在构造查询之后调用这些方法中的任何一种: |
1 | DB::table( 'notice' )->aggregate( 'sum' , [ 'notice_id' ]); |
numericAggregate
方法调用aggregate,将结果转数字
1 | DB::table( 'notice' )->numericAggregate( 'sum' , [ 'notice_id' ]); |
insert
插入 返回布尔值
1 2 | Notice::insert([ 'title' => 'ad' ]); Notice::insert([ 'title' => 'ad' , 'a' => 1]); |
insertGetId
插入 返回id
1 | Notice::insertGetId([ 'title' => 'ad' ]); |
update
更新 返回布尔值
1 2 | $notice = Notice::find(1); $notice ->update([ 'title' => 'ad' ]); |
updateOrInsert
更新或插入
1 | Notice::updateOrInsert([ 'title' => 'ad' ], [ 'content' => 'adcd' ]); |
1 | increment<br>加,字符串会被转成0,然后加1 |
1 2 | Notice::increment( 'title' ); //该字段加1 Notice::increment( 'title' , 6); //该字段加6 |
decrement
1 | 加,字符串会被转成0,然后1 |
1 2 | Notice::decrement( 'title' ); //该字段减1 Notice::decrement( 'title' , 6); //该字段减6 |
1 | delete <br>删除 |
1 2 | $notice = Notice::find(1); return $notice -> delete (); |
truncate
如果希望截断整个表,该表将删除所有行,并将自动递增ID重置为零,则可以使用截断方法:
1 | DB::table( 'notice' )->truncate(); |
newQuery
获取查询生成器的新实例。
1 2 | $query = ( new Notice())->newQuery(); return $query ->find(1); |
raw
若要创建原始表达式,可以使用Db::raw方法
1 | DB::table( 'notice' )->select(DB::raw( 'count(*) as notice_count' ))->get(); |
__call
当方法不存在时,抛异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public function __call( $method , $parameters ) { if ( static ::hasMacro( $method )) { return $this ->macroCall( $method , $parameters ); } if (Str::startsWith( $method , 'where' )) { return $this ->dynamicWhere( $method , $parameters ); } $className = static :: class ; throw new BadMethodCallException( "Call to undefined method {$className}::{$method}()" ); } |
Illuminate\Database\Query\Builder 加载的代码块
Illuminate\Database\Concerns\BuildsQueries
chunk
如果你需要处理成千上万个 Eloquent 结果,可以使用 chunk 命令。chunk 方法会获取一个“组块”的 Eloquent 模型,并将其填充到给定闭包进行处理。使用 chunk 方法能够在处理大量数据集合时能够有效减少内存消耗:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | $noticeRes = [ 'success' => 0, 'fail' => 0, ]; $notice = DB::table( 'notice' )->orderBy( 'notice_id' )->chunk(500, function ($notices) use (&$noticeRes) { foreach ($notices as $notice) { if ($notice->status == 1){ $noticeRes[ 'success' ]++; } else { $noticeRes[ 'fail' ]++; } } }); var_dump($notice); var_dump($noticeRes); exit(); |
each
在分组时对每个项执行回调,查询结果为值(value),chunk方法需要循环,each方法内部做了循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | $noticeRes = [ 'success' => 0, 'fail' => 0, ]; $notice = DB::table( 'notice' ) ->orderBy( 'id' ) ->each( function ( $notice_value , $notice_key ) use (& $noticeRes ) { if ( $notice_value ->status){ $noticeRes [ 'success' ]++; } else { $noticeRes [ 'fail' ]++; } }, 500); var_dump( $notice ); var_dump( $noticeRes ); exit (); |
下面是Illuminate\Database\Eloquent\Builder类的大部分方法
fromQuery
应该只有复杂查询要写原生的时候才会用到
1 2 | Notice::fromQuery( "select title from notice" ); Notice::fromQuery( 'select title from notice WHERE title = ?' , [1]); |
findMany
1 2 | Notice::findMany([1,2], [ 'title' ]); Notice::findMany(1, [ 'title' ]); |
findOrFail
这个查不到会直接抛出ModelNotFoundException异常,可以在App\Exceptions\Handler定制异常捕捉
1 | Notice::findOrFail(100); |
findOrNew
这个查不到会通过newModelInstance方法新建一个模型对象
1 | Notice::findOrNew(100); |
firstOrNew
这个查不到会通过newModelInstance方法新建一个模型对象,并把参数一(array)$attributes {array}$values 合为一个数组赋给模型
1 2 | Notice::firstOrNew([ 'title' => 14]); Notice::firstOrNew([ 'title' => 100], [ 'content' => 123]); |
newModelInstance
这个方法在比较后,因为前面有用到,所以先讲下
创建模型,根据传入的数组赋值
1 | Notice::newModelInstance([ 'title' => 100, 'content' => 123]); |
firstOrCreate
查询或新建一条记录,第一个参数为查询条件,如果找不到,会把参数一(array)$attributes {array}$values 合为一个数组赋值,新建一条记录并返回模型
1 | Notice::firstOrCreate([ 'title' => 14], [ 'content' => 123]); |
updateOrCreate
更新或新建一条记录,第一个参数为查询条件,找到则把第二个参数的值赋给查到的model,如果找不到,会先执行firstOrNew($attributes)方法,创建对象,然后把{array}$values通过fill($values)赋值再执行save()保存
1 | Notice::UpdateOrCreate([ 'title' => 14], [ 'content' => 1234]); |
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 | /** * Create or update a record matching the attributes, and fill it with values. * * @param array $attributes * @param array $values * @return \Illuminate\Database\Eloquent\Model */ public function updateOrCreate(array $attributes, array $values = []) { return tap($ this ->firstOrNew($attributes), function ($instance) use ($values) { $instance->fill($values)->save(); }); } |
注:tap是laravel内置的一个方法,简单实用 https://segmentfault.com/a/1190000008447747
1 2 3 4 5 6 | function tap($value, $callback) { $callback($value); return $value; } |
firstOrFail
查到返回对象,否则抛ModelNotFoundException异常
1 2 | Notice::firstOrFail(); Notice:: where ( 'title' , 321)->firstOrFail(); |
firstOr
查询一条,不存在则执行自定义$callback方法,
firstOr($columns = ['*'], Closure $callback = null)
$callback可以在参数一或参数二传,方法有对第一个参数做实现Closure类的判断
1 2 3 4 | $title = 1; return Notice:: where ( 'title' , 100)->firstOr(function() use ($title) { return Notice::UpdateOrCreate([ 'title' => $title], [ 'content' => 1234]); }); |
with
表关联查询
model
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Notice{ public function uploadRelation() { return $this ->hasMany(UploadRelation:: class , 'relation_id' , 'id' ) ->where( 'relation_type' , '=' , UploadRelation::RELATION_TYPE_NOTICE) ->select( 'relation_type' , 'relation_id' , 'upload_id' ); } } class UploadRelation{ public function upload() { return $this ->hasOne(Upload:: class , 'id' , 'upload_id' ); } } |
调用关联
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | Notice::with( 'uploadRelation' )->get(); Notice::with( 'uploadRelation.upload' )->get(); Notice::with([ 'uploadRelation' => function ( $query ){ $query ->select( 'relation_id' , 'upload_id' ); } ])->get(); Notice::with([ 'uploadRelation' => function ( $query ){ $query ->select( 'relation_id' , 'upload_id' )->with([ 'upload' => function ( $query ){ $query ->select( 'id' , 'path' ); } ]); } ])->get(); |
without
用来注销绑定
1 2 | Notice::with( 'uploadRelation' )->get(); Notice::with( 'uploadRelation' )->without( 'uploadRelation' )->get(); |
withCount
只获取关联条数
1 | Notice::withCount( 'uploadRelation' )->get(); |
null
1 2 | ->whereNotNull( 'updated_at' ); ->whereNull( 'updated_at' ); |
实用:
数据库:查询生成器(Database: Query Builder):https://laravel.com/docs/5.6/queries
Laravel API Builder:https://laravel.com/api/5.3/Illuminate/Database/Eloquent/Builder.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 高级Join方法 如果 join 方法的约束条件比较复杂,可以使用闭包函数的方式指定 DB::table( 'users' ) -> join ( 'contacts' , function ($ join ) { $ join -> on ( 'users.id' , '=' , 'contacts.user_id' )->orOn(...); }) -> get (); 如果 join 约束中要使用列值与指定数组比较,则可以使用 where 和OrWhere方法 DB::table( 'users' ) -> join ( 'contacts' , function ($ join ) { $ join -> on ( 'users.id' , '=' , 'contacts.user_id' ) -> where ( 'contacts.user_id' , '>' , 5); }) -> get (); |
高级join:https://segmentfault.com/a/1190000005792605
转载自:
Lumen 数据库操作orm:https://www.jianshu.com/p/492e1cb1eb28
Lumen 数据库操作orm之表关联hasOne(hasMany)和belongsTo(belongsToMany):https://www.jianshu.com/p/d11e5f84a699
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端
· 因为Apifox不支持离线,我果断选择了Apipost!