thinkphp-模型定义、新增、删除、更新、查询

4202次阅读 126人点赞 作者: WuBin 发布时间: 2024-04-11 09:43:59
扫码到手机查看

模型基础

定义

定义一个和数据库表向匹配的模型;

namespace app\model;
use think\Model;

class User extends Model
{
    
}

在控制器中引用:

namespace app\controller;
// 引用model文件夹下的User.php文件
use app\model\User;

class DataModel{
    public function index() {
       return json(User::select());
    }
}

模型会自动对应数据表,并且有一套自己的命名规则,模型类需要去除表前缀(tp_),采用驼峰式命名,并且首字母大写;

tp_user(表名) => User
// 有两个下划线就去掉表前缀tp,然后首字母大写
tp_user_type(表名) => UserType

可以直接使用模型的名称User::*调用查询方法,比如select()等;

如果在phpstorm中没有代码提示,把5.1 的模型注释复制过来;

如果担心设置的模型类名和PHP 关键字冲突,可以开启应用类后缀;比如,我要将原来的model/User.php以及其类改为UserModel.php,

app/UserModel.php 模型

namespace app\model;
use think\Model;

class UserModel extends Model
{
    
}

控制器 controller/DataModel.php

namespace app\controller;

use app\model\UserModel;

class DataModel{
    public function index() {
       return json(UserModel::select());
    }
}

如果仅仅修改名称,那么会报错,这时候就需要在模型中添加一个私有属性$name,然后设置一下$name 属性为指定user(表名)即可实现;

namespace app\model;
use think\Model;

class User extends Model
{
     // 添加后缀需要设置模式名称
     protected $name = 'user';
}

修改模型中的主键

默认根据id进行查找,比如:

User::find(19) 查找id=19的行

但是我们可以在模型中指定查询的主键

namespace app\model;
use think\Model;

class User extends Model
{
    // 设置主键
    protected $pk = 'uid';
}

修改后,find(19)就变成了要查找的uid=19。

从控制器端调用模型操作,如果和控制器类名重复,可以设置别名,在控制器中:

namespace app\controller;

use app\model\User as UserModel;

class DataModel{
    public function index() {
       return json(UserModel::find(19));
    }
}

因为项目大了,很多类名都会重复,所以很多商业代码都使用别名as进行区分。

在模型定义中,可以设置其它的数据表;

namespace app\model;
use think\Model;

class User extends Model
{
// 设置表,默认表是当前名称的表 这里User 对应tp_user表 设置在config/database.php中
// 但是也可以设置指向其他的表 注意这里要写表全名
    protected $table = 'tp_one';
}

但是一般不建议这么操作,要求模型与表一一对应。

模型和控制器一样,也有初始化,在这里必须设置static 静态方法;

namespace app\model;
use think\Model;

class User extends Model
{
    // 初始化操作
    protected static function init()
    {
        parent::init();
        echo '初始化操作';
    }
}

初始化操作即为:第一次实例化的时候执行init,只要调用了这个model,那么就会执行这个初始化操作。

模型的新增和删除

使用实例化的方式添加一条数据,首先实例化方式如下,两种均可:

use app\model\User as UserModel;
$user = new UserModel();
$user = new \app\model\User();

设置要新增的数据,然后用save()方法写入到数据库中,save()返回布尔值;

$user = new UserModel();
$user->username = '李白';
$user->password = '123';
$user->gender = '男';
$user->email = 'libai@163.com';
$user->price = 100;
$user->details = '123';
$user->uid = 1011;
// 保存就是新增
$user->save();

也可以通过save()传递数据数组的方式,来新增数据;

$user->save([
    'username' => '李白',
    'password' => '123',
    'gender' => '男',
    'email' => 'libai@163.com',
    'price' => 100,
    'details' => '123',
    'uid' => 1011
]);

使用allowField()方法,允许要写入的字段,其它字段就无法写入了;

$user->allowField(['username', 'password'])
    ->save([
        'username' => '李白',
        'password' => '123',
        'gender' => '男',
        'email' => 'libai@163.com',
        'price' => 100,
        'details' => '123',
        'uid' => 1011
    ]);

这时执行,会报错:General error: 1364 Field 'details' doesn't have a default value,意思就是details是数据表必填字段,没有设置默认值,所以改一下:

$user->allowField(['username', 'password', 'details'])
    ->save([
        'username' => '李白',
        'password' => '123',
        'gender' => '男',
        'email' => 'libai@163.com',
        'price' => 100,
        'details' => '123',
        'uid' => 1011
    ]);

这时候执行插入后,发现数据表中最新数据:

idusernamepasswordgenderemailpricedetailsuidstatus
316李白123null0.00123null0

所以像email等不允许写入的字段就会是Null或者是使用创建数据表时候指定的默认值。

DROP TABLE IF EXISTS `tp_user`;
CREATE TABLE `tp_user`  (
  `id` mediumint(8) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自动编号',
  `username` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `password` char(40) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `gender` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '男',
  `email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `price` decimal(8, 2) UNSIGNED NOT NULL DEFAULT 0.00,
  `details` text CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `uid` smallint(6) NULL DEFAULT NULL,
  `status` tinyint(3) NOT NULL DEFAULT 0 COMMENT '状态',
  `list` json NULL,
  `delete_time` datetime(0) NULL DEFAULT NULL,
  `create_time` datetime(0) NOT NULL DEFAULT '1997-01-01 01:01:01' COMMENT '创建时间',
  `update_time` datetime(0) NOT NULL DEFAULT '1997-01-01 01:01:01' COMMENT '修改时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 302 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

模型新增也提供了replace()方法来实现REPLACE into 新增,默认是insert into;

$user = new UserModel();
$user->username = '李白';
$user->password = '123';
$user->gender = '男';
$user->email = 'libai@163.com';
$user->price = 100;
$user->details = '123';
$user->uid = 1011;
$user->replace()->save();
return Db::getLastSql();

SQL:REPLACE INTO `tp_user` SET `username` = '李白' , `password` = '123' , `gender` = '男' , `email` = 'libai@163.com' , `price` = '100' , `details` = '123' , `uid` = 1011 , `create_time` = '2024-04-12 10:37:42.840691' , `update_time` = '2024-04-12 10:37:42.840698'

使用saveAll()方法,可以批量新增数据,返回批量新增的数组

$dataAll = [
    [
        'username' => '李白1',
        'password' => '123',
        'gender' => '男',
        'email' => 'libai@163.com',
        'price' => 100,
        'details' => '123',
        'uid' => 1011
    ],
    [
        'username' => '李白2',
        'password' => '123',
        'gender' => '男',
        'email' => 'libai@163.com',
        'price' => 100,
        'details' => '123',
        'uid' => 1011
    ]
];
dump($user->saveAll($dataAll));

最终返回的是一个Collection数据集,其中关于新插入行的所有字段数据在:-data:array: 属性中可以查看到。

当新增成功后,使用$user->id,可以获得自增ID(主键需是id);

如果是像上例一样插入的是多行,那么返回的就是null,dump($user->id);

推荐使用::create()静态方法,来创建要新增的数据(只能创建一行,无法创建多行);

$user = UserModel::create(
    //参数1 是新增数据数组,必选
    [
        'username' => '李白3',
        'password' => '123',
        'gender' => '男',
        'email' => 'libai@163.com',
        'price' => 100,
        'details' => '123',
        'uid' => 1011
    ],
    //参数2 是允许写入的字段 allowField,可选,默认为[]
    ['username', 'password', 'details'],
    // 参数3 为是否replace 新增,默认false 为Insert 写入,改为true则为replace新增,
    false
);

删除

使用find()方法,通过主键(id)查询到想要删除的数据;

然后再通过delete()方法,将数据删除,返回布尔值;

// 首先要查询到一条数据
$user = UserModel::find(322);
// 返回的是一个布尔值 删除成功返回true
dump($user->delete());

也可以使用静态方法调用destroy()方法,通过主键(id)删除数据;

 UserModel::destroy(321);

静态方法destroy()方法,也可以批量删除数据;

dump( UserModel::destroy([319, 320]) );

静态destroy()方法删除成功返回true。

通过数据库类的查询条件删除

UserModel::where('id', '>', 80)->delete();
UserModel::where('username', '=', '李白6')->delete();

使用闭包的方式进行删除;

UserModel::destroy(function($query) {
            $query->where('username', '=', '李白3')->delete();
});

更新

使用find()方法获取数据,然后通过save()方法保存修改,返回布尔值

// 首先找到一条
$user = UserModel::find(325);
// 然后执行修改
$user->username = '董存瑞';
$user->email = 'iloveu@163.com';
// 更新和新建都是用save
$user->save();

通过where()方法结合find()方法的查询条件获取的数据,进行修改;

$user = UserModel::where('username', '李黑')->find();
$user->username = '李白';
$user->email = 'libai@163.com';
$user->save();
save()方法只会更新变化的数据,如果提交的修改数据没有变化,则不更新;但如果你想强制更新数据,即使数据一样,那么可以使用force()方法
dump( $user->force()->save() ); // 返回布尔值

Db::raw()执行SQL 函数的方式,同样在这里有效,如果有复杂的操作,就用raw包含一下:

// 首先找到一条
$user = UserModel::find(325);
// 然后执行修改
$user->username = '董存瑞';
$user->email = 'iloveu@163.com';
$user->price = Db::raw('price + 1');
// 更新和新建都是用save
dump( $user->force()->save() );

每次刷新都会给数据库price属性+1

使用allowField()方法,允许要更新的字段,其它字段就无法写入了;

// 首先找到一条
$user = UserModel::find(325);
// 然后执行修改
$user->username = '董存瑞';
$user->email = 'iloveu@163.com';
$user->price = 200;
// 这样price字段会修改成功 因为设置了price字段允许更新
dump( $user->allowField(['username', 'price'])->force()->save() );

如果像下面这样,更新操作会返回true,但是price字段不会更新,因为只允许username字段更新。

$user->price = 200;
dump( $user->allowField(['username'])->force()->save() );

但是tp6目前有个bug,在6.1.4版本下实测:

$user->price = Db::raw('price + 1');
// $user->price = 200;
dump( $user->allowField(['username'])->force()->save() );

使用Db::raw,会忽略allowField中关于允许字段的设置,allowField中没有设置price,那么price依然会每次执行+1操作。

通过saveAll()方法,可以批量修改数据,返回被修改的数据集合;

$list = [
    ['id' => 316, 'username' => '白+黑', 'email' => 'baihei@163.com'],
    ['id' => 317, 'username' => '白+黑', 'email' => 'baihei@163.com'],
    ['id' => 318, 'username' => '白+黑', 'email' => 'baihei@163.com']
];
$user = new UserModel();
$user->saveAll($list);
批量更新saveAll()只能通过主键id 进行更新;

使用静态方法::update()更新,返回的是对象实例;

UserModel::update([
    // 必须要有id的放在第一个位置上,作为查询条件
    'id' => 316,
    'username' => '李白',
    'email' => 'bai@163.com'
]);

第二种,将查询条件放在updata([], 查询条件)

UserModel::update([
    'username' => '李白',
    'email' => 'bai@163.com'
], ['id' => 317]);

第三个参数,限制了修改的字段,比如这里仅仅传入了username,此时更新的时候只会更新Username字段,email字段的内容不会被更改。

UserModel::update([
    'username' => '李白白',
    'email' => 'bai@163.com'
], ['id' => 318], ['username']);
模型的新增和修改都是save()进行执行的,它采用了自动识别体系来完成。实例化模型后调用save()方法表示新增,查询数据后调用save()表示修改;当然,如果在save()传入更新修改条件后也表示修改(比如传入了id);
// 比如此例,没有传入Id,然后也实例化模型了,那么此时就是新增
$user = new UserModel();
$user->save([
    'username' => '宋江',
    'password' => 123,
    'details' => 321,
    'email' => 'jiang@163.com',
    'price' => 200
]);

查询

模型数据查询与普通的数据库查询几乎一样。但是也多了很多方便的新功能。

使用find()方法,通过主键(id)查询到想要的数据;

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

也可以使用where()方法进行条件筛选查询数据;

$user = UserModel::where('username', '辉夜')->find();
return json($user);
调用find()方法时,如果数据不存在则返回Null,还有findOrEmpty()方法,数据不存在返回空模型(其实就是一个数组),此时,可以后使用isEmpty()方法来判断,是否为空模型。
$user = UserModel::findOrEmpty(419); // 不存在返回空数组[]
if($user->isEmpty()) {
    echo '空的';
}

使用select([])方式,查询多条指定id 的字段,不指定就是所有字段(select[]是直接给查出结果了,如果在查询阶段还是使用whereIn);

$user = UserModel::select([19, 20, 21]); // 实际上相当于where in
return json($user);

模型方法也可以使用where 等连缀查询,和数据库查询方式一样

$user = UserModel::where('status', 1) // status=1的行
                  ->limit(3) // 只能显示3条
                  ->order('id', 'desc') // 按照Id倒叙排列
                  ->select();

获取某个字段value()或者某个列column()的值;

// 找到id=19的行(数组)中的username字段的值
$user = UserModel::where('id', '=', 19)->value('username');
$user = UserModel::whereIn('id', [19,20,21])->column('username', 'id');

找到id范围在19、20、21的3条数据并显示出他们的username列的数据,结果中以其id字段的值作为键值

[
19: "蜡笔小新",
20: "路飞",
21: "黑崎一护"
]

同时column的第二个参数可以去掉,那么结果就仅仅是值了。

$user = UserModel::whereIn('id', [19,20,21])->column('username');
/*
 [
"蜡笔小新",
"路飞",
"黑崎一护"
]
 */

模型支持动态查询:getBy*,*表示字段名;

idusernameemail
1辉夜wubin-work@qq.com
2辉夜huiye@163.com
UserModel::getByUsername('辉夜');
UserModel::getByEmail('huiye@163.com');
getBy*查找,只会查找出一条!!即从上到下查询到的第一条,比如本例就会查找到id=1的那一条的辉夜!

如果要查找倒叙的第一条,就要使用order-desc了

// 查找出id=2的倒数第一条
$user = UserModel::order('id', 'desc')->getByUsername('李白');

模型支持聚合查询:max、min、sum、count、avg 等

// 查找出price列中的最大值
$user = UserModel::max('price');

使用chunk()方法可以分批处理数据,数据库查询时讲过,防止一次性开销过大

UserModel::chunk(5, function($users) {
    foreach($users as $user) {
        echo $user->username . ' | ';
    }
    echo '<br>...<br>';
});

第一个参数5,意思就是每5条执行一次

可以看到结果如下:

蜡笔小新 | 路飞 | 黑崎一护 | 小明 | 孙悟饭 |
...
孙悟天 | 樱桃小丸子 | 孙武 | 李白 | 辉夜 |
...
李黑 | 辉夜 | 辉夜 | 白居易 | 辉夜 |
...
李逵 | 礼拜 | 公孙 | 李白 | 李白 |
...
李白 | 李白 | 李白白 | 董存瑞 | 宋江 |
...

可以利用游标查询功能,可以大幅度减少海量数据的内存开销,它利用了PHP 生成器特性。每次查询只读一行,然后再读取时,自动定位到下一行继续读取;

foreach(UserModel::where('id', '<', 100)->cursor() as $user) {
    echo $user->username . ' | ';
}

最终结果:蜡笔小新 | 路飞 | 黑崎一护 | 小明 | 孙悟饭 | 孙悟天 | 樱桃小丸子 | 孙武 | 李白 | 辉夜 |

可以看到它是一行一行的读取并处理的。

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

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

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

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

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

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

    几个高级前端常用的API

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

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

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

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

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

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

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

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

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

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

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

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

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

    Vue+html2canvas截图空白的问题

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

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

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

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

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