thinkphp-关联模型初步、一对一关联查询、一对多关联查询

4208次阅读 147人点赞 作者: WuBin 发布时间: 2024-05-07 14:33:27
扫码到手机查看

关联模型

关联模型,顾名思义,就是将表与表之间进行关联和对象化,即合并两张表的数据,然后进行增删改查的操作。

比如以下两张表,tp_user 表,主键为:id;附属表:tp_profile,建立两个字段:user_id 和hobby,外键是user_id;

tp_user

idusernamepassword
12科比123
23杜兰特321

tp_profile

iduser_idhobby
112孙悟天
213科比

一般主表存放一些经常存取的信息,附表存放一些不常用的额外信息,从而节约资源。

现在我们需要根据主表查找到附表的一些信息。

第一步就是要建立表之间的关联关系:tp_profile的user_id与tp_user的id必须是对应的

第二步就是创建User 模型和Profile 模型,均为空模型;

model/User.php

<?php
namespace app\model;
use think\Model;

class User extends Model {

}

model/Profile.php

<?php
namespace app\model;
use think\Model;

class Profile extends Model {

}

关联有正向关联(主表关联附表),也有反向关联(附表关联主表)。

正向关联:User 模型端(主),需要关联Profile(附),具体方式如下:

<?php
namespace app\model;
use think\Model;

class User extends Model {
    // 与表名一一对应
    public function profile()
    {
        //hasOne 表示一对一关联,参数一表示附表,参数二外键,默认user_id
        return $this->hasOne(Profile::class);
    }

}

Profile类依然保持空即可。

然后新建控制器controller/Grade.php

<?php
namespace app\controller;
use app\model\User as UserModel;

class Grade {

    public function index()
    {
        $user = UserModel::find(12);
        return json($user->profile);
        // 找到附表中的某一条属性的值
        echo $user->profile->hobby;
    }
}

这里如果直接json($user)是看不到profile表中字段内容的,如果要获取profile表中对应的内容,就需要$user-profile。

当然主类中也可以改名,但是相应的控制器中获取的也要改(建议名称都保持一致):

class User extends Model {
    // 与表名一一对应
    public function profileAAA()
    {
        //hasOne 表示一对一关联,参数一表示附表,参数二外键,默认user_id
        return $this->hasOne(Profile::class);
    }

}

echo $user->profileAAA->hobby;

关于外键:

namespace app\model;
use think\Model;

class User extends Model {
    // 与表名一一对应
    public function profile()
    {
        //hasOne 表示一对一关联,参数一表示附表,参数二外键,默认user_id
        return $this->hasOne(Profile::class, 'user_id');
    }

}

外键就是附表中与主表相关联的属性。如果默认是User_id那么就可以省略不写,当不是user_id的时候,就需要手动指定。

对于关联方式,系统提供了9 种方案,具体如下:

hasOne一对一
belongTo一对一
hasMany一对多
hasOneThrough远程一对一
belongsToMany多对多
morphMany多态一对多
morphOne多态一对一
morphTo多态
hasManyThrough远程一对多

常用的也就是上面标红的三种,一对多:一篇文章对应它的多条评论。多对多:一个用户对应很多种角色(审核人员、主管)然而审核人员又对应了科比,杜兰特等人;

一对一关联反向操作

在model/profile.php中

namespace app\model;
use think\Model;

class Profile extends Model {
    public function user()
    {
        return $this->belongsTo(User::class, 'user_id');
    }
}

在控制器中

namespace app\controller;
use app\model\User as UserModel;
use app\model\Profile as ProfileModel;

class Grade {

    public function index()
    {
        $profile = ProfileModel::find(1);
        echo $profile->user->username;
    }
}

正反向关联也就是关联关系和相对的关联关系

一对一hasOnebelongsTo
一对多hasManybelongsTo
多对多belongsToManybelongsToMany

一对一关联查询

hasOne模式

hasOne 模式,适合主表关联附表

hasOne('关联模型',['外键','主键']);
return $this->hasOne(Profile::class,'user_id', 'id');

关联模型(必须):关联的模型名或者类名

外键:默认的外键规则是当前模型名(不含命名空间,下同)+_id ,例如user_id

主键:当前模型主键,默认会自动获取也可以指定传入

关联修改

比如现在需要通过主表user中的id找到关联的附表对应的行 并修改其内容

在控制器中:

 $user = UserModel::find(19);
$user->profile->save([
            'hobby' => '酷爱科比'
]);

关联新增

通过主表id找到关联附表中对应行 如果没有关联行就新增

$user = UserModel::find(19);
 $user->profile()->save([
            'hobby' => '酷爱橘艾莱娜'
 ]);

这时候我们会发现,如果附表中原本存在关联行的情况下,这样执行依然会在附表中新增一条,这就会变成一对多了

所以就需要在附表中先判断,user_id存在不存在,否则会直接新增一条。

->profile 属性方式可以修改数据,->profile()方法方式可以新增数据;

belongsTo模式

belongsTo 模式,适合附表关联主表,具体设置方式如下(反向操作):

belongsTo('关联模型',['外键','关联主键']);
return $this->belongsTo(Profile::class,'user_id', 'id');

关联模型(必须):模型名或者模型类名

外键:当前模型外键,默认的外键名规则是关联模型名+_id关联

主键:关联模型主键,一般会自动获取也可以指定传入

反向关联

使用hasOne()也能模拟belongsTo()来进行查询,即hasOne也能实现反向查询,这样就不需要belongs方法了:

参数一表示的是User 模型类的profile 方法,而非Profile 模型类

// id=1代表的是z找到附表的id=1的行
$user = UserModel::hasWhere('profile', ['id' => 1])->find();
return $user;

通过profile模型 找到附表id=1的行 找出来 然后找到对应的主表的id=19的值

采用闭包,这里是两张表操作,会导致id 识别模糊,需要指明表

使用闭包好处就是可以自定义SQL查询语句,实现更多的操作。

$user = UserModel::hasWhere('profile', function($query) {
            $query->where('id', '=', 1);
})->find();
return $user;

一对多关联查询

hasMany

hasMany 模式,适合主表关联附表,实现一对多查询

hasMany('关联模型',['外键','主键']);
return $this->hasMany(Profile::class,'user_id', 'id');

关联模型(必须):模型名或者模型类名

外键:关联模型外键,默认的外键名规则是当前模型名+_id

主键:当前模型主键,一般会自动获取也可以指定传入

比如在模型中


namespace app\model;
use think\Model;

class User extends Model {
    // 一对多
    public function profile()
    {
        return $this->hasMany(Profile::class, 'user_id');
    }
}

控制器中

 $user = UserModel::find(19);
return json($user->profile);

最终会返回如下形式:

[
{
id: 1,
user_id: 19,
hobby: "酷爱科比",
status: 1
},
{
id: 37,
user_id: 19,
hobby: "不喜欢吃青椒",
status: 1
},
{
id: 46,
user_id: 19,
hobby: "酷爱橘艾莱娜",
status: 0
}
]

所以一对一跟一对多在查询方面的区别就是,一对多最终返回的是一个数组,返回的是多条;而一对一只会返回一条;

使用->profile()方法模式,可以进一步进行数据的筛选

$user = UserModel::find(19);
return json($user->profile()->select());

注意,这里如果仅仅使用$user->profile()是不会有任何结果返回的,必须配合->select()

$user->profile()->select() 
效果等价于
$user->profile

使用方法可以对结果进行链式查询,增加条件

return json($user->profile()->where('id', '>=', 10)->select());

使用has()方法,查询关联附表的主表内容(从附表查询主表的内容),比如大于等于2 条的主表记录;

UserModel::has('profile', '>=', 2)->select();

意思是:要在附表中查找,有两条以上主表关联的数据,一条的就不搜出来

附表:

iduser_idgrade
119xxx
24xxx
319xx

主表

id(user_id)content
19uu
 $user = UserModel::find(19);
return json($user->has('profile', '>=', 2)->select());

最终返回的是查询到的主表信息,就是主表中id=19的行在附表中有两条关联数据。

[
{
id: 19,
username: "蜡笔小新",
password: "123"
}
]

使用hasWhere()方法,查询关联附表筛选后记录,比如兴趣审核通过的主表记录

UserModel::hasWhere('profile', ['status'=>1])->select();

使用save()和saveAll()进行关联新增和批量关联新增

给附表中,新增一条/多条,并指定附表中user_id=19

新增一条

$user->profile()->save(['hobby'=>'测试喜好', 'status'=>1]);

新增多条

$user = UserModel::find(19);
        $user->profile()->saveAll([
            [
                'hobby' => 'ceshi1',
                'status' => 1
            ],
            [
                'hobby' => 'ceshi2',
                'status' => 1
            ]
        ]);

关联删除

比如要在删除主表中的信息时候,也要链带将附表中的关联信息也一起删掉

使用together()方法,可以删除主表内容时,将附表关联的内容全部删除;

// 关联删除
$user = UserModel::with('profile')->find(331);
// 注意together参数是一个数组,是可以关联多个附表,就是将多个附表中user_id=xx的都删除
$user->together(['profile'])->delete();

注意,这里如果->find(331),而id=331在主表中不存在的话,系统会报错。

一对多,是没有修改的。

点赞 支持一下 觉得不错?客官您就稍微鼓励一下吧!
关键词:thinkphp
推荐阅读
  • uniapp实现被浏览器唤起的功能

    当用户打开h5链接时候,点击打开app若用户在已经安装过app的情况下直接打开app,若未安装过跳到应用市场下载安装这个功能在实现上主要分为两种场景,从普通浏览器唤醒以及从微信唤醒。

    9603次阅读 623人点赞 发布时间: 2022-12-14 16:34:53 立即查看
  • Vue

    盘点Vue2和Vue3的10种组件通信方式

    Vue中组件通信方式有很多,其中Vue2和Vue3实现起来也会有很多差异;本文将通过选项式API组合式API以及setup三种不同实现方式全面介绍Vue2和Vue3的组件通信方式。

    4297次阅读 317人点赞 发布时间: 2022-08-19 09:40:16 立即查看
  • JS

    几个高级前端常用的API

    推荐4个前端开发中常用的高端API,分别是MutationObserver、IntersectionObserver、getComputedstyle、getBoundingClientRect、requ...

    14452次阅读 948人点赞 发布时间: 2021-11-11 09:39:54 立即查看
  • PHP

    【正则】一些常用的正则表达式总结

    在日常开发中,正则表达式是非常有用的,正则表达式在每个语言中都是可以使用的,他就跟JSON一样,是通用的。了解一些常用的正则表达式,能大大提高你的工作效率。

    13504次阅读 491人点赞 发布时间: 2021-10-09 15:58:58 立即查看
  • 【中文】免费可商用字体下载与考证

    65款免费、可商用、无任何限制中文字体打包下载,这些字体都是经过长期验证,经得住市场考验的,让您规避被无良厂商起诉的风险。

    12024次阅读 964人点赞 发布时间: 2021-07-05 15:28:45 立即查看
  • Vue

    Vue3开发一个v-loading的自定义指令

    在vue3中实现一个自定义的指令,有助于我们简化开发,简化复用,通过一个指令的调用即可实现一些可高度复用的交互。

    16384次阅读 1307人点赞 发布时间: 2021-07-02 15:58:35 立即查看
  • JS

    关于手机上滚动穿透问题的解决

    当页面出现浮层的时候,滑动浮层的内容,正常情况下预期应该是浮层下边的内容不会滚动;然而事实并非如此。在PC上使用css即可解决,但是在手机端,情况就变的比较复杂,就需要禁止触摸事件才可以。

    15187次阅读 1234人点赞 发布时间: 2021-05-31 09:25:50 立即查看
  • Vue

    Vue+html2canvas截图空白的问题

    在使用vue做信网单页专题时,有海报生成的功能,这里推荐2个插件:一个是html2canvas,构造好DOM然后转canvas进行截图;另外使用vue-canvas-poster(这个截止到2021年3月...

    29876次阅读 2349人点赞 发布时间: 2021-03-02 09:04:51 立即查看
  • Vue

    vue-router4过度动画无效解决方案

    在初次使用vue3+vue-router4时候,先后遇到了过度动画transition进入和退出分别无效的情况,搜遍百度没没找到合适解决方法,包括vue-route4有一些API都进行了变化,以前的一些操...

    25924次阅读 1995人点赞 发布时间: 2021-02-23 13:37:20 立即查看
交流 收藏 目录