当前位置: 首页 > news >正文

ThinkPHP一对多的关联模型运用

一、序言

最近在写ThinkPHP关联模型的时候一些用法总忘,我就想通过写博客的方式复习和整理下一些用法。

具体版本:

  • topthink/framework:6.1.4
  • topthink/think-orm:2.0.61

二、实例应用

1、一对多的关联

本文案例:一个用户对应多篇文章,一篇文章对应多条评论。

以下是用户、文章、评论的模型建立:

(1)用户模型

<?php
/*** Created by PhpStorm* Author: fengzi* Date: 2023/12/19* Time: 14:50*/namespace app\common\model;/*** 用户模型*/
class UserModel extends ComBaseModel
{protected $name='user';/*** 文章关联表:一对多* hasMany()* 第一个参数:要关联的模型类* 第二个参数:在关联表中表示当前模型的外键名* 第三个参数:当前模型(userModel)的主键名* @return \think\model\relation\HasMany* @Author: fengzi* @Date: 2024/7/3 11:40*/public function article(){return $this->hasMany(ArticleModel::class,'user_id','id');}/*** 评论表模型:远程一对多关联* hasManyThrough()* 第一个参数(必须):关联的模型类* 第二个参数(必须):中间表的模型类* 第三个参数:在中间模型中表示当前模型的外键* 第四个参数:在关联模型中表示当前模型的外键* 第五个参数:当前模型主键* 第六个参数:中间模型主键* @return \think\model\relation\HasManyThrough* @Author: fengzi* @Date: 2024/7/3 11:42*/public function articleComment(){return $this->hasManyThrough(ArticleCommentModel::class, ArticleModel::class, 'user_id', 'user_id', 'id', 'id');}
}

(2)文章模型

<?php
/*** Created by PhpStorm* Author: fengzi* Date: 2023/12/19* Time: 14:50*/namespace app\common\model;/*** 文章模型*/
class ArticleModel extends ComBaseModel
{protected $name='article';/*** 用户模型* belongsTo()* 第一个参数:关联模型类* 第二个参数:在当前模型(ArticleModel)中表示关联模型(UserModel)的外键* 第三个参数:关联模型主键* @return \think\model\relation\BelongsTo* @Author: fengzi* @Date: 2024/7/3 13:54*/public function user(){return $this->belongsTo(UserModel::class, 'user_id', 'id');}/*** 评论关联表:一对多* hasMany()* 第一个参数:要关联的模型类* 第二个参数:在关联表中表示当前模型的外键名* 第三个参数:当前模型(ArticleModel)的主键名* @return \think\model\relation\HasMany* @Author: fengzi* @Date: 2024/7/3 11:40*/public function comment(){return $this->hasMany(ArticleCommentModel::class, 'article_id', 'id');}}

(3)评论模型

<?php
/*** Created by PhpStorm* Author: fengzi* Date: 2023/12/19* Time: 14:50*/namespace app\common\model;/*** 文章评论模型*/
class ArticleCommentModel extends ComBaseModel
{protected $name='article_comment';/*** 评论模型* belongsTo()* 第一个参数:关联模型类* 第二个参数:在当前模型(ArticleCommentModel)中表示关联模型(ArticleModel)的外键* 第三个参数:关联模型主键* @return \think\model\relation\BelongsTo* @Author: fengzi* @Date: 2024/7/3 13:54*/public function article(){return $this->belongsTo(ArticleModel::class, 'article_id', 'id');}}

2、一对多查询:

(1)一对多的简单查询示例

public function many()
{// 实例化模型$userModel = app(UserModel::class);$articleModel = app(ArticleModel::class);$articleCommentModel = app(ArticleCommentModel::class);/** 关联查询 */// 查询ID=1的用户$user = $userModel->find(1);dump($user->toArray());// 查询ID=1的用户的所有文章,【article()】就是UserModel模型中定义的关联方法$article = $user->article()->select()->toArray();dump($article);/** 根据关联条件查询 */// 查询评论大于等于4个的文章,【comment】就是ArticleModel模型中定义的【comment()】关联方法$lists = $articleModel->has('comment','>=',4)->select()->toArray();dump($lists);// 查询评论评论来源为APP的文章(评论来源source:1web,2App),【comment】就是ArticleModel模型中定义的【comment()】关联方法$lists = $articleModel->hasWhere('comment',['source'=>2])->select()->toArray();dump($lists);/** 复杂的关联条件查询 */// 当有复杂的查询条件时,可以先通过评论表进行查询,把查询结果的对象当作条件,再关联文章表// 不需要select()或find()方法进行查询,直接返回查询对象即可$articleCommentWhere = $articleCommentModel->where([['source', '=', 2], ['content', 'like', '%有点耐%'], ['user_id', '=', 1]]);// 【comment】就是ArticleModel模型中定义的【comment()】关联方法$lists = $articleModel->hasWhere('comment', $articleCommentWhere)->select()->toArray();dd($lists);
}

(2)一对多的预查询加载

  • 一对多关联查询的时候只能用【with()】,不能用【withJion()】。
  • 当用户模型(UserModel)中关联文章变成一对一的时候【return $this->hasOne(ArticleModel::class,'user_id','id');】,【with()】和【withJion()】两个都可以使用。但需注意以下几点:
    • 使用with()的时候,关联数据可以正常输出,withCount()等方法可以同时使用。
    • 使用withJoin()的时候,关联数据可以正常输出,但withCount()等方法不可以同时使用。
  • withCount()、withSum()、withAvg()、withMax()等类似的方法所输出的字段格式为:关联名称(article)+ “_” + [count | sum | avg | max]。例如:article_count
public function many()
{// 实例化模型$userModel = app(UserModel::class);// 查询ID=1的用户,关联查询文章,【article】就是UserModel模型中定义的关联方法$userWith = $userModel->with(['article'])->withCount(['article'])->withSum(['article'], 'read_num')->withAvg(['article'], 'read_num')->withMax(['article'], 'read_num')->find(1)->toArray();dump($userWith);// 查询ID=1的用户,关联查询文章,【article】就是UserModel模型中定义的关联方法$userWithJon = $userModel->withJoin(['article'])->withCount(['article'])->withSum(['article'], 'read_num')->withAvg(['article'], 'read_num')->withMax(['article'], 'read_num')->find(1)->toArray();dd($userWithJon);
}

  • 关联查询使用闭包时,如果只需显示关联模型中的几个字段,field() 方法中必须带上两个模型中的关联字段(下图中的关联字段就是UserModel模型中article()里面的第二个参数[ user_id ])。当然,带上关联字段后,关联字段也会显示出来。
  • 关联查询使用闭包时,如果要过滤关联模型中的几个字段不显示,使用 withoutField() 方法。这时就不用带上关联字段。

3、一对多关联新增

常用新增的使用(下图有执行插入操作后的数据情况),我总共使用了四种方法进行插入,下图可以看见结果。

  • 使用【insert】和【insertGetId】虽说可以插入关联,但是关联字段[ user_id ]不会自动写入数据。而且在设置了自动写入时间的情况下,[ create_time ] 和 [ update_time ] 也没有数据。
  • 使用【save】可以插入关联数据,也可以自动写入关联字段[ user_id ]和[ create_time ] 和 [ update_time ] 的数据。【saveAll】也是可行的。
  • 使用【create】不能写入数据,会直接报错。
  • 从用户模型添加关联数据到文章模型时,我们只需要在用户模型中设置关联模式。在关联模型(ArticleModel)中的相对关联不是必须设置的。
    /*** 用户模型中的文章关联:一对多(必须设置才能实现关联数据的添加)* hasMany()* 第一个参数:要关联的模型类* 第二个参数:在关联表中表示当前模型的外键名* 第三个参数:当前模型(userModel)的主键名* @return \think\model\relation\HasMany* @Author: fengzi* @Date: 2024/7/3 11:40*/public function article(){return $this->hasMany(ArticleModel::class,'user_id','id');}
    
    /*** 文章模型中相对关联的用户模型(通过用户模型添加文章的关联数据时非必须)* belongsTo()* 第一个参数:关联模型类* 第二个参数:在当前模型(ArticleModel)中表示关联模型(UserModel)的外键* 第三个参数:关联模型主键* @return \think\model\relation\BelongsTo* @Author: fengzi* @Date: 2024/7/3 13:54*/public function user(){return $this->belongsTo(UserModel::class, 'user_id', 'id');}
    
public function many()
{// 实例化模型$userModel = app(UserModel::class);// 查询ID=10的用户$user = $userModel->find(10);// 使用insert添加ID=10用户的关联文章$user->article()->insert(['title' => '厦门旅游', 'status' => 1]);// 使用insertGetId添加ID=10用户的关联文章$user->article()->insertGetId(['title' => '黄山旅游', 'status' => 2]);// 使用save添加ID=10用户的关联文章$user->article()->save(['title' => '泰山旅游', 'status' => 1]);// 使用create添加ID=10用户的关联文章$user->article()->create(['title' => '泰山旅游', 'status' => 2]);dd($user->toArray());
}

4、一对多关联删除

一对多的关联删除跟【ThinkPHP一对一关联模型的运用(ORM)】文章中的【1.6.1、with 的关联删除】小节差不多,在此就不在重复赘述了。

在此我再补充一些细节:

  • 关联删除的时候用select()方法查出来的数据不能用together()进行关联数据的删除。
  • 链式操作的方式使用together()的时候一定要注意一个细节:前面查找的数据一定不能为空,不然链式操作直接跟together()会报错( Call to a member function together() on null )。
  • 必须以查询结果的对象进行together()操作(使用find()方法后获取到一个查询结果对象)。不能直接条件查询后进行together()操作,不然会报错“method not exist:think\db\Query->together”。
    public function many()
    {// 实例化模型$userModel = app(UserModel::class);// 正确使用:必须以查询结果的对象进行together()操作,使用find()方法后获取到一个查询结果对象。$res = $userModel->with(['article'])->where('id', 1)->find()->together(['article'])->delete();// 错误使用:不能直接条件查询后进行together()操作,不然会报错“method not exist:think\db\Query->together”$res = $userModel->with(['article'])->where('id', 1)->together(['article'])->delete();dd($res);
    }
    

 5、一对多的关联编辑

一对多的关联编辑跟【ThinkPHP一对一关联模型的运用(ORM)】文章中的【1.5、with 关联修改】小节差不多,在此就举几个简单的例子:

public function many()
{// 实例化模型$userModel = app(UserModel::class);// 获取用户ID=4的信息$res = $userModel->with(['article'])->where('id', 4)->find();// 打印修改前的数据dump($res->toArray());// 修改用户名$res->name = 'xiaohuang';
// 保存修改$res->save();// 添加标题为“海口旅游攻略”的新文章$res->article()->save(['title' => '海口旅游攻略']);// 修改文章ID=7的阅读量$res->article()->save(['id'=>7, 'read_num' => 1000]);// 查询打印修改后的数据$info = $userModel->with(['article'])->where('id', 4)->find();dd($info->toArray()); }

相关文章:

  • ClickHouse | 入门
  • 2024 年实验室设备管理系统的选择指南
  • 第四章-课后练习5:修正指数曲线模型——excel和python应用(2)
  • 力扣 简单 104.二叉树的最大深度
  • Llama 系列简介与 Llama3 预训练模型推理
  • springboot实战学习(9)(配置mybatis“驼峰命名“和“下划线命名“自动转换)(postman接口测试统一添加请求头)(获取用户详细信息接口)
  • 【数据治理-设计数据标准】
  • py-mmcif包pdbx_struct_assembly对象介绍
  • 困扰我们的,不是如何过上更幸福的生活,而是如何过上比别人更幸福的生活
  • Linux之实战命令18:col应用实例(五十二)
  • 开启争对目标检测的100类数据集-信息收集
  • 深入理解 Nuxt.js 中的 app:data:refresh 钩子
  • 「实战应用」如何用DHTMLX Gantt集成工具栏部件更好完成项目管理?
  • js设计模式-工厂模式 单例模式 观察者模式 发布订阅模式 原型模式 代理模式 迭代器模式
  • GPU参数指标
  • CNN 在图像分割中的简史:从 R-CNN 到 Mask R-CNN
  • Laravel 菜鸟晋级之路
  • Laravel核心解读--Facades
  • MySQL的数据类型
  • Mysql数据库的条件查询语句
  • Nginx 通过 Lua + Redis 实现动态封禁 IP
  • node-sass 安装卡在 node scripts/install.js 解决办法
  • Python中eval与exec的使用及区别
  • ReactNative开发常用的三方模块
  • SpringCloud(第 039 篇)链接Mysql数据库,通过JpaRepository编写数据库访问
  • vue-loader 源码解析系列之 selector
  • vue的全局变量和全局拦截请求器
  • 从PHP迁移至Golang - 基础篇
  • 从输入URL到页面加载发生了什么
  • 代理模式
  • 技术:超级实用的电脑小技巧
  • 那些被忽略的 JavaScript 数组方法细节
  • 那些年我们用过的显示性能指标
  • 数组的操作
  • 微服务入门【系列视频课程】
  • 我看到的前端
  • 写代码的正确姿势
  • 译有关态射的一切
  • 找一份好的前端工作,起点很重要
  • 白色的风信子
  • 浅谈sql中的in与not in,exists与not exists的区别
  • ​埃文科技受邀出席2024 “数据要素×”生态大会​
  • #Datawhale AI夏令营第4期#AIGC方向 文生图 Task2
  • #include到底该写在哪
  • #前后端分离# 头条发布系统
  • $jQuery 重写Alert样式方法
  • (¥1011)-(一千零一拾一元整)输出
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (solr系列:一)使用tomcat部署solr服务
  • (超详细)2-YOLOV5改进-添加SimAM注意力机制
  • (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画...
  • (限时免费)震惊!流落人间的haproxy宝典被找到了!一切玄妙尽在此处!
  • (学习日记)2024.02.29:UCOSIII第二节
  • (转)LINQ之路