laravel 使用with预加载(渴求加载)的使用方法示例及嵌套查询示例
with()方法能做什么?在什么场景使用?
1.情景如下。2张数据表 主表userinfors用户表【id,name,created_at】,从表文章表articles表【id,user_id,title,content,created_at】
3.需求:根据当前登录用户A获取A所发布的文章。
4.模型之间的关系:一对多,一个用户能有多篇文章。
表结构
1.主表(userinfors)
2.从表(articles)
代码实现(根据当前登录用户,获取用户下的所有相关文章)
1.创建model(这里就不在赘述)
2.在主表model(userinfor表)模型中创建一对多关联关系
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Tests\Controllers\UserController;
/**
* 前端用户模型
* Class UserInfor
* @package App\Models
*/
class UserInfor extends Model
{
use HasFactory;
//与模型关联的表名
protected $table = 'userinfors';
//不准批量复制的属性请填写在下放数组中
protected $guarded = [];
//模型序列化:Date 类型转换
protected $casts = [
'created_at' => 'date:Y-m-d H:i:s',
'updated_at' => 'date:Y-m-d H:i:s',
];
/**
* 用户模型一对多关联用户动态表
* 一个用户拥有多条的动态数据
* 参数1:要关联的模型(从表)
* 参数2:存在于从表中的那个与userinfor(主表)关联的字段
* 参数3:存在于主表中的那个与 从表进行关联的字段名
*/
public function article_hasMany()
{
return $this->hasMany(Article::class,'user_id','id');
}
}
3.在控制器Controller中实现with
<?php
namespace App\Http\Controllers\Api\V1;
use App\Http\Controllers\BaseController;
use App\Http\Controllers\Controller;
use App\Models\Article;
use App\Models\UserInfor;
use Illuminate\Http\Request;
/**
* 用户动态控制器
* Class UserDynamicController
* @package App\Http\Controllers\Api\V1
*/
class ArticleController extends Controller
{
//获取当前登录用户动态列表
public function getMyDynamicList(Request $request){
//接收必要参数
$page = $request['page'] ?? 1;//分页
$limit = 2;//每页数据条数
$offset = $page * $limit - $limit;//从第几条开始读取 默认为第0条
//查询当前用户动态数据(倒序排列)
$user_id = UserInfor::where('id',1);//获取当前登录的用户模型
//查询当前用户下的文章,并进行分页,每页2条数据,按文章的创建时间进行倒序排列。
$data_list = $user_id->with(['article_hasMany'=>function($query) use($offset,$limit){
//注意:在这个闭包里面的调用的字段均为被关联的model中的字段(也就是存在于从表中的字段,无需考虑从表字段名与主表字段名重复的问题。)
//如下面的示例:$query->orderBy('从表中的created_at','desc')->offset($offset)->limit($limit);
$query->orderBy('created_at','desc')->offset($offset)->limit($limit);
}])->first();
dd($data_list->toArray());//laravel框架自带的打印函数,效果等同于下方2行代码。
//var_dump($data_list->toArray());
//die;
}
}
4.返回数据结构
array:25 [
"id" => 1
"created_at" => null
"name" => "刘通"
"articles" => array:2 [
0 => array:5 [
"id" => 2
"created_at" => "2020-10-26 10:36:59"
"user_id" => 1
"title" => "作家A-2"
"content"=>"内容A-2内容A-2内容A-2内容A-2"
]
1 => array:5 [
"id" => 1
"created_at" => "2020-10-22 12:36:59"
"user_id" => 1
"title" => "作家A-1"
"content"=>"内容A-1内容A-1内容A-1内容A-1"
]
]
]
4.总结:
简单说下我为什么要用这个with()方法:这是因为他压缩了mysql查询语句,将查询语句变为2条。
第一条查指定用户。
第二条查所有的指定文章。
sql只跑了2遍。
而常规套路会跑N+1遍
第一遍查指定用户。
第二遍查指定文章。
第…查指定文章。
第N边查指定文章。
这样做对数据库不是很友好,缺点大家都明白,我不在赘述了。
5.实战代码
//获取当前登录用户动态列表
public function getMyDynamicList(Request $request){
//接收必要参数
$page = $request['page'] ?? 1;//分页
$limit = 12;//每页数据条数
$offset = $page * $limit - $limit;//从第几条开始读取 默认为第0条
//查询当前用户动态数据(倒序排列)
$user_infor = UserInfor::where('token',$request['token']);
$data_list = $user_infor->with(['userDynamics'=>function($query) use($offset,$limit){
$query->orderBy('created_at','desc')->offset($offset)->limit($limit);
$query->withCount('userDynamicComments as connent_count');//参数1,模型中的关联方法名,as * 表示返回值的别名
$query->withCount('userDynamicAdmiress as admiress_count');
}])->select('id','nickname','pic_url')->first();
}
with循环嵌套用法
1.使用场景:当3张关联时想要循环嵌套应该怎么写。
举一个不恰当的例子!
假设情景:现有3张表分别为 A:书籍表,B:评论表,C:评论者电话表。
表关系:注意:同一本书只能被同一个人评论一次!(也就是一本书可以有多条评论,但每条评论的评论者只能和这本书产生一次关联!)
书籍表(一)对 评论表(多) = 一对多关联。
评论表(一) 对 评论者(一) = 一对一关联。
需求:已知书籍id与指定评论id,现根据书籍id查询得出评论内容以及评论者电话数据
表结构图下:
A:书籍表(book)
id | name(书籍名称) |
---|---|
1 | 我的php文档 |
2 | 我的加班历史 |
3 | 我的工作记录 |
B:评论表(comment)
id | comment(评论内容) | book_id(书记表关联id) | tel_id(电话表关联id) |
---|---|---|---|
1 | 这本书真的很厚 | 1 | 18 |
2 | 看的我眼睛都花了 | 1 | 43 |
3 | 这真的是日常记录吗?写的好详细 | 2 | 69 |
C:评论者电话表(tel)
id | comment_id(评论表id) | tel(评论者电话号码) |
---|---|---|
18 | 1 | 183******3645 |
… | … | … |
43 | 2 | 133******2625 |
… | … | … |
69 | 3 | 131******1661 |
2.使用with()代码实现循环嵌套查询
//根据指定书籍id 与 指定评论id 获取当前书籍数据。
public function getBookParticulars(Request $request){
//接收书籍id
$book_id = $request->book_id;//书籍id
$comment_id = $request->comment_id;//指定评论id
//bookComment = 书籍Book模型自定一对多关联评论方法的名称
//commentTel = 评论内容表一对一关联评论者电话表
$book = Book::where('id',$book_id)->with(['bookComment'=>function($query) use ($comment_id){
//$comment_id 前端传递给php方法的参数,需要use才能在with中使用
$query->where('id',$comment_id)//这里的id指的是comment表中的id
#->with('commentTel:id,tel')//嵌套写法A 这行代码中的‘id’是评论者电话表(tel)的id,不写这个id可能会导致没有查询结果
//commentTel是评论对评论者的方法名
->with(['commentTel'=>function($query2){
$query2->first();
}])//嵌套写法B
->first();
}])->first();
dd($book);//打印数据查看结果
}