ThinkPHP6.0学习笔记-模型操作
ThinkPHP模型
模型定义
在app
目录下创建Model
目录,即可创建模型文件
定义一个和数据库表相匹配的模型
use think\Model;
class User extends Model
{
}
User
会自动匹配对于数据库中的数据表tp_user
模型命名后缀,是为了防止关键字冲突,可以开启应用类后缀:创建
Class UserModel
use think\Model; class UserModel extends Model
{
//指向数据表
protected $name = 'user';
protected $table = 'tp_user';
}
模型类的定义需要去除表前缀,采用驼峰式命名首字母大写
tp_user ==> User
tp_user_type ==> UserType
创建于数据表相匹配的模型类后,可以在使用User::*
方法来调用数据库进行操作
namespace app\controller;
use think\facade\Db;
use app\model;
class DataTest
{
public function index()
{
$user = model\User::select();
return json($user);
}
}
设置模型
模型中默认的主键为id
,也可以在模型类中设置主键字段名$pk
protected $pk = 'uid';
在控制器中调用模型操作,发生重名可以设置别名
use app\model\User as UserModel;
模型类中可以定义指向数据库表
protected $table = 'tp_user'; //包含前缀
protected $name = 'user'; //不含前缀
模型类初始化操作(控制器也有),但是必须设置static
静态方法
protected static funtion init()
{
echo "初始化";
}
模型设置属性:
属性 | 描述 |
---|---|
name | 指向数据表名(无前缀),默认为当前模型名 |
table | 数据表 |
suffix | 数据表后缀(默认为空) |
pd | 设置数据表主键字段名(默认为id ) |
connection | 数据库连接(默认加载数据库配置database.php ) |
query | 模型使用的查询类名称 |
field | 指定允许操作的字段(支持数组) |
schema | 模型对应数据表字段和类型 |
type | 模型需要自动转换的字段和类型 |
strict | 是否严重区分字段大小(默认true) |
disuse | 数据表废弃字段 |
模型字段
模型的数据字段和对应的数据表字段是对应的,默认会自动获取(以及类型),自动获取的过程会加一次查询操作(浪费资源),thinkphp支持自定义字段信息。
$schema = [
'[字段名]' => '[字段类型]';
]
schema
需要定义整个数据表字段,对单个字段定义需要自动转换的类型可以使用type
如果需要废弃(忽略)数据表中的字段,可以使用$disuse
来定义
protected $disuse = [‘type’,'status'];
获取数据
$user = User::find(1);
echo $user->create_time;
echo $user->name;
由于模型类实现了ArrayAccess
接口,所以可以当成数组使用。
$user = User::find(1);
echo $user['create_time'];
echo $user['name'];
如果你是在模型内部获取数据的话,需要改成:
$user = $this->find(1);
echo $user->getAttr('create_time');
echo $user->getAttr('name');
模型赋值、 实例化
给模型对象赋值
$user = new User() ;
$user->table = 'tp_user';
$user->score = 100 ;
上述代码会将模型对象打包赋值给$user
,可以对其封装的模型对象进行操作“修改器”
同时也可以使用
$data['name'] = 'thinkphp';
$data['score'] = 100;
$user = new User($data);
或者使用
$user = new User();
$data['name'] = 'thinkphp';
$data['score'] = 100;
$user->data($data);
data
方法支持使用修改器
$user = new User();
$data['name'] = 'thinkphp';
$data['score'] = 100;
$user->data($data, true);
如果需要对数据进行过滤,可以使用
$user = new User();
$data['name'] = 'thinkphp';
$data['score'] = 100;
$user->data($data, true, ['name','score']);
表示只设置data
数组的name
和score
数据。
最佳操作实践
新增操作:
新增数据的最佳实践原则:使用create
静态方法新增数据,使用saveAll
批量新增数。
删除操作:
删除的最佳实践原则是:如果删除当前模型数据,用delete
方法,如果需要直接删除数,使用destroy
静态方法。
更新操作:
更新的最佳实践原则是:如果需要使用模型事件,那么就先查询后更新,如果不需要使用事件或者不查询直接更新,直接使用静态的Update
方法进行条件更新,如非必要,尽量不要使用批量更新。
新增-save()
模型数据的新增和数据库的新增数据有所区别,数据库的新增只是单纯的写入给定的数据,而模型的数据写入会包含修改器、自动完成以及模型事件等环节,数据库的数据写入参考数据库章节。
第一步:实例化模型对象
$user = new UserModel();
$user = new \app\model\UserModel();
第二步:新增数据
public function index()
{
$user = new model\UserModel();
$user->username = '诸葛大力';
$user->password = 'gouzaizai';
$user->gender = '女';
$user->email = 'chengguo@gmail.com';
$user->price = 100 ;
$user->uid = 0000;
$user->details = '000';
$user->save();
}
上述的只是一个普通方法,除此还有传递数据数组的方式
public function index()
{
$user = new model\UserModel();
$data = [
'username' => '诸葛大力',
'password' => 'gouzaizai',
'gender' => '女',
'email' => 'chengguo@gmail.com',
'price' => 100 ,
'uid' => 0000,
'details' => '000',
];
$user->save($data);
}
allowField()
限制写入允许字段
$user
// 限制只允许写入‘username、password’字段
->allowField(['username','password'])
->save($data);
replace()
新增
实现REPLACE into
新增(修改新增)
$user->replace()->save($data);
如果$data
数据表已存在会更新;
REPLACE INTO `tp_user` SET `id` = 301 , `username` = '诸葛大力' , `password` = 'gouzaizai' , `gender` = '女' , `email` = 'chengguo@gmail.com' , `price` = 100 , `uid` = 0 , `details` = '000' , `create_time` = '2020-04-10 11:40:20.660840' , `update_time` = '2020-04-10 11:40:20.660840'
获取自增ID
$user->id;
$user->uid;
……
批量新增数据saveAll()
*
可以批量添数据,返回新增数组
$user = new User;
$list = [
['name'=>'thinkphp','email'=>'thinkphp@qq.com'],
['name'=>'onethink','email'=>'onethink@qq.com']
];
$user->saveAll($list);
saveAll方法新增数据返回的是包含新增模型(带自增ID)的数据集对象。
saveAll
方法新增数据默认会自动识别数据是需要新增还是更新操作,当数据中存在主键的时候认为是更新操作。
静态方法 create()
*
$user = UserModel::create([
'username' => '李白',
'password' => '123',
'gender' => '男',
'email' => 'libai@163.com',
'price' => 100,
'details' => '123',
'uid' => 1011
], ['username', 'password', 'details'], false);
参数 1 是新增数据数组,必选
参数 2 是允许写入的字段,可选
参数 3 为是否 replace 写入,默认 false 为 Insert 写入
新增数据的最佳实践原则:使用create
方法新增数据,使用saveAll
批量新增数据。
删除-delete()
删除当前模型
$user = new User();
$user->delete();
根据主键删除
User::destroy(1);
User::destroy([1,2,3]);
条件删除
User::where('id',10)->delete();
User::destroy(function($query){
$query->where('id',10);
});
删除的最佳实践原则是:如果删除当前模型数据,用delete
方法,如果需要直接删除数据,使用destroy
静态方法。
更新
使用find()
方法获取数据,通过save()
方法提交修改
$user = new model\UserModel();
$data = [
'username' => '诸葛大力',
'gender' => '女'
];
$user->find(305)->save($data);
使用where()
方法结合find()
方法设置查询条件并获取数据
$user = new model\UserModel();
$data = [
'username' => '齐天大圣'
];
$user->where('username','孙悟空')
->find()->save($data);
save()
只会更新数据有区别的地方;强制使用save()
更新数据需要使用force()
Db::raw()
执行SQL函数方法同样可以实现更新
$user = model\UserModel::find(305);
$user->price = Db::raw('price+10');
$user->save();
使用allowField()
方法,允许要更新的字段
$user = model\UserModel::find(305);
$data = [
'username' => '李白',
'password' => '123',
'gender' => '男',
'email' => 'libai@163.com',
'price' => 100,
'details' => '123',
'uid' => 1011
];
$user->allowField(['username'])->save($data);
使用saveAll()
方法可以批量修改数据,返回被修改数据集;批量saveAll()
更新只可以通过主键来进行
静态方法::update()
更新
$data = [ 'username=> '李白',
'password' => '123',
'gender' => '男',
'email' => 'libai@163.com',
'price' => 100,
'details' => '123',
'uid' => 1011
];
model\UserModel::update($data,['id'=> 304],['username']);
参数 1 是数据数组,必选
参数 2 更新条件,可选
参数 3 是允许写入的字段,可选
save()
模型的新增、更新都需要
save()
进行执行,具有自动识别;实例化模型后调用
save()
表示新增,查询数据后调用save()
表示修改
更新的最佳实践原则是:如果需要使用模型事件,那么就先查询后更新,如果不需要使用事件或者不查询直接更新,直接使用静态的Update
方法进行条件更新,如非必要,尽量不要使用批量更新。
查询
模型普通查询
使用
find()
通过主键查询想要的数据(可以在模型类中设置主键字段)调用
find()
方法是,如果数据不存在返回Null,使用findOrEmpty()
方法,数据不存返回空模型使用
isEmpty()
方法判断是否为空模型使用
where()
进行条件筛选查询使用
select()
方法,查询多条指定主键的字段,不指定就是全部字段$user = model\UserModel::select([304,305]);
foreach ($user as $key=>$value)
{
echo $value->username;
}
支持查询构造器的各种方法
模型动态查询
getBy[字段名]
:可以获取对应字段的value(驼峰命名,字段首字母大写)
$user = model\UserModel::getByUsername('李白');
模型聚合查询
支持max
min
sum
count
avg
等方法
UserModel::max('price');
模型分批查询
支持使用chunk()
进行分批处理数据
User::chunk(100, function ($users) {
foreach($users as $user){
// 处理user模型对象
}
});
模型游标查询
支持使用cursor()
方法进行游标查询,返回生成器对象
foreach(User::where('status', 1)->cursor() as $user){
echo $user->name;
}
user
变量是一个模型对象实例。
模型查询的最佳实践原则是:在模型外部使用静态方法进行查询,内部使用动态方法查询,包括使用数据库的查询构造器。
模型获取器
获取器的作用是对模型实例的数据做出自动处理
每一个获取器对应模型的一个特殊方法,方法要求public
获取器命名规范
get[FieldName]Attr()
,FieldName为数据表字段的驼峰转换,定义了获取器自动触发
- 模型的数据对象取值操作
$model->field_name
- 模型的序列化输出操作
$model->toArray()
- 显式调用
getAttr
方法$this->getAttr('field_name')
获取器常见场景以及基本使用
- 时间日期字段的格式化输出
- 集合或枚举类型的输出
- 数字状态字段的输出
- 组合字段的输出
// 状态值的转换输出
// 模型类
public function getStatusAttr($value)
{
$status = [-1=>'删除' , 0=>'禁用' , 1=>'正常' , 2=>"待审核"];
return $status[$value];
}
// 控制端
$user = model\UserModel::find(19);
return $user->status;
通俗理解:
在控制端正常的查看字段值,模型类定义一个获取器(一个字段可以对应一个模型类中的特殊方法获取器方法)),获取器就会对控制端的字段查询进行获取并进行自定义的处理方法。
获取器还可以定义数据表不存在的字段,在控制端用户可以正常的按照字段名读取的方式来访问
<?php
namespace app\model;
use think\Model;
class User extends Model
{
public function getStatusTextAttr($value,$data)
{
$status = [-1=>'删除',0=>'禁用',1=>'正常',2=>'待审核'];
return $status[$data['status']];
}
}
获取器方法的第二个参数传入的是当前的所有数据数组。
我们就可以直接使用status_text字段的值了,例如:
$user = User::find(1);
echo $user->status_text; // 例如输出“正常”
这里也就是为了解决多种处理方法并规避冲突的写法;因为如果获取器定义以后就无法在控制端获原始的字段值,不过也还有另外一种getData()
方法获得原始字段值:
$user = User::find(1);
// 通过获取器获取字段
echo $user->status;
// 获取原始字段数据
echo $user->getData('status');
// 获取全部原始数据
dump($user->getData());
动态获取器
可以支持对模型使用动态获取器,无需在模型类中定义获取器方法,在控制端使用动态获取器:
$user = model\UserModel::find(19)
->withAttr('status',function($value,$data){
$status = [
-1=>'删除',0=>'禁用',
1=>'正常',2=>'待审核'
];
return $status[$value];
});
echo $user->status;
withAttr
方法支持多次调用,定义多个字段的获取器。另外注意,withAttr
方法之后不能再使用模型的查询方法,必须使用Db类的查询方法。
模型修改器
模型修改器的左右:对模型设置对象的值进行处理
在新增数据的时候,可以利用修改器对数据进行格式化、转换等处理;处理数据新增,还有数据更新也可能触发修改器
模型修改器命名规范:
setFieldNameAttr()
ps:修改器只对模型方法有效
public function setEmailAttr($value)
{
return strtolower($value);
}
$user = model\UserModel::create([
'username' => '李白',
'password' => '123',
'gender' => '男',
'email' => 'LIBai@163.com',
'price' => 100,
'details' => '123',
'uid' => 1011
], ['username', 'password', 'details','email'], false);
echo $user->save();
查询范围
在模型类创建一个封装的查询和写入方法,有便于控制端调用
查询封装方法 scope()
前缀scope
,后缀自定义,在调用时吧后缀当做参数即可。
public function scopeMale($query)
{
$query->where('gender','男')
->field('id,username,gender,email')
->limit(5);
}
$user = model\UserModel::scope('male')->select();
return "<hr>".Db::getLastSql()."<hr>".$user;
public function scopeEmail($query, $value)
{
$query->where('email','like','%'.$value.'%');
}
$user = UserModel::scope('email','xiao')->select();
return "<hr>".Db::getLastSql()."<hr>".$user;
scope()
的第一个参数是调用的封装方法,第二个参数是封装方法可以接收的数据
支持多个查询封装方法连缀调用
$user = UserModel::scope('email','xiao')
->scope('price',80)
->select();
return "<hr>".Db::getLastSql()."<hr>".$user;
在使用查找范围
scope()
后,指定使用find()
select()
查询;在模型类中的查询封装方法中可以使用包括修改器、获取器等在内的模型操作方法。
public function getGenderAttr($value,$data)
{
$gender = ['男'=>'纯爷们','女'=>'小姑娘'];
return $gender[$value];
} public function scopeMale($query)
{
$query->where('gender','男')
->field('id,username,gender,email')
->limit(5);
}
全局查找范围
支持在模型中设置globaScope
属性,定义全局查找范围
class User extends Model
{
// 定义全局的查询范围
protected $globalScope = ['status'];
public function scopeStatus($query)
{
$query->where('status',1);
}
}
然后,执行下面的代码:
$user = User::find(1);
最终的查询条件会是
status = 1 AND id = 1
如果需要动态关闭所有的全局查询范围,可以使用:
// 关闭全局查询范围
User::withoutGlobalScope()->select();
可以使用withoutGlobalScope
方法动态关闭部分全局查询范围。
User::withoutGlobalScope(['status'])->select();
模型搜索器
搜索器用于封装字段或搜索标识的表达式,类似查找范围
一个搜索器对应模型的一个特殊方法
命名规范
search[FieldName]Attr()
User模型定义name
字段和时间字段的搜索器,可以使用:
class User extends Model
{
public function searchNameAttr($query, $value, $data)
{
$query->where('name','like', $value . '%');
}
public function searchCreateTimeAttr($query, $value, $data)
{
$query->whereBetweenTime('create_time', $value[0], $value[1]);
}
}
然后,我们可以使用下面的查询
User::withSearch(['name','create_time'], [
'name' => 'think',
'create_time' => ['2018-8-1','2018-8-5'],
'status' => 1
])->select();
最终生成的SQL语句类似于
SELECT * FROM `think_user` WHERE `name` LIKE 'think%' AND create_time` BETWEEN '2018-08-01 00:00:00' AND '2018-08-05 00:00:00'
可以看到查询条件中并没有status
字段的数据,因此可以很好的避免表单的非法查询条件传入,在这个示例中仅能使用name
和create_time
条件进行查询。
事实上,除了在搜索器中使用查询表达式外,还可以使用其它的任何查询构造器以及链式操作。
例如,你需要通过表单定义的排序字段进行搜索结果的排序,可以使用
class User extends Model
{
public function searchNameAttr($query, $value, $data)
{
$query->where('name','like', $value . '%');
if (isset($data['sort'])) {
$query->order($data['sort']);
}
}
public function searchCreateTimeAttr($query, $value, $data)
{
$query->whereBetweenTime('create_time', $value[0], $value[1]);
}
}
然后,我们可以使用下面的查询
User::withSearch(['name','create_time', 'status'], [
'name' => 'think',
'create_time' => ['2018-8-1','2018-8-5'],
'status' => 1,
'sort' => ['status'=>'desc'],
])
->select();
最终查询的SQL可能是
SELECT * FROM `think_user` WHERE `name` LIKE 'think%' AND `create_time` BETWEEN '2018-08-01 00:00:00' AND '2018-08-05 00:00:00' ORDER BY `status` DESC
你可以给搜索器定义字段别名,例如:
User::withSearch(['name'=>'nickname','create_time', 'status'], [
'nickname' => 'think',
'create_time' => ['2018-8-1','2018-8-5'],
'status' => 1,
'sort' => ['status'=>'desc'],
])
->select();
搜索器通常会和查询范围进行比较,搜索器无论定义了多少,只需要一次调用,查询范围如果需要组合查询的时候就需要多次调用
模型数据集
数据集直接继承collection
类,和数据的数据集方式一样、操作一样。
参照官方技术文档
模型自动时间戳
系统支持自动写入创建和更新的时间戳字段(默认会关闭),具体配置方法:
全局开启:在
database.php
文件中修改auto_timestamp
为truely在模型类中单独开启自动时间戳:
$autoWriteTimestamp
class User extends Model
{
protected $autoWriteTimestamp = true;
}
也或者单独关闭自动时间戳
class User extends Model
{
protected $autoWriteTimestamp = false;
}
配置开启后会自动添加自动时间戳写入
create_time
和update_time
两个
端,默认的类型是int,如果是时间类型,可以设置如下
protected $autoWriteTimestamp = [自动时间戳字段]
同时也可以自定义两个自动时间戳:
protected $createTime = '[字段]';
protected $updateTime = '[字段]';
只读字段
在模型类中定义readonly
属性:静态
protected $readonly = ['字段1','字段2',……]
动态设置制度字段:
$user->readonly(['字段1',……])->save();
系统转换
系统可以通过模型端设置写入或读取时对字段类型进行转换type
php rotected $type = [ 'price' => 'integer', 'status' => 'boolean', ;
设置废弃字段 $disuse
JSON字段 *
数据库JSON
数据库写入JSON字段,直接通过数组方式即可完成:
data = [
'username' => '李白',
'password' => '123',
'gender' => '男',
'email' => 'LIBai@163.com',
'price' => 100,
'details' => '123',
'list' => ['username'=>李白,'gender'=>'女']
];
Db::table('tp_user')
->json(['list']) // 定义list字段为json类型字段
->insert($data)
查询数据,需要转换JSON数据格式:
Db::table('tp_user')->json(['list'])->find(288);
将JSON字段里的数据作为查询条件
$user = Db::table('tp_user')->json(['list'])->where('list-username','李白')->find();
修改JSON字段数据
$data['list'] = ['username'=>'李白','gender'=>'男'];
Db::table('tp_user')->json(['list'])->where('id',220)->update($data);
模型JSON
设置写入JSON字段的字符字段:
protetced $json = ['list'];
使用模型方法新增JSON数据的字段
$user = new User;
$user->name = 'thinkphp';
$user->info = [
'email' => 'thinkphp@qq.com',
'nickname '=> '流年',
];
$user->save();
具体的请参考官方文档JSON部分
模型软删除
在实际项目中,对数据频繁使用删除操作会导致性能问题,软删除的作用就是把数据加上删除标,而不是真正的删除,同时也便于需要的时候进行数据的恢复。
要使用软删除功能,需要引入SoftDelete
trait,例如User模型按照下面的定义就可以使用软删除功能:
use SoftDelete ;
rotected $deleteTime = 'delete_time';
delete_time
默认为Null,类型为时间戳类型,用于记录数据的删除时间。
确定开启软删除和字段后
// 软删除
User::destroy(1);
// 真实删除
User::destroy(1,true);
$user = User::find(1);
// 软删除
$user->delete();
// 真实删除
$user->force()->delete();
软删除后系统会忽略该条数据,模型会自动屏蔽数据
使用
withTrashed()
取消屏蔽软删除的数据使用
onlyTrashend()
可以查询被软删除的数据使用
restore()
可以恢复被软删除的数据如果需要强制删除,需要使用
force()
强制安排
模型和数据库的事件
数据库事件
执行增删改查操作的时候,可以同时出发一些事件来执行额外的操作;额外的操作事件可以部署在构造方法中等待激活后执行;数据库事件方法是Db::event('事件名','执行函数')
事件名 | 描述 |
---|---|
before_select | select 查询前回调 |
before_find | find 查询前回调 |
after_insert | insert 操作后回调 |
after_update | update 操作后回调 |
after_delete | delete 操作后回调 |
一般情况下,数据库事件卸载控制器端的初始化方法里,有利于统一管理
public function initialize()
{
Db::event('before_select', function($query){
echo "执行了批量的查询操作"
});
}
模型事件
事件 描述 事件方法名
after_read 查询后 onAfterRead
before_insert 新增前 onBeforeInsert
after_insert 新增后 onAfterInsert
before_update 更新前 onBeforeUpdate
after_update 更新后 onAfterUpdate
before_write 写入前 onBeforeWrite
after_write 写入后 onAfterWrite
before_delete 删除前 onBeforeDelete
after_delete 删除后 onAfterDelete
before_restore 恢复前 onBeforeRestore
after_restore 恢复后 onAfterRestore
在模型类中使用静态方法调用即可完`成事件触发
关联模型
关联模型:将数据表与表之间进行关联和对象化;
关联方式
关联方式 | 描述 |
---|---|
hasOne |
一对一关联 |
belongsTo |
一对一关联-反向 |
hasMany |
一对多关联 |
hasOneThrough |
远程一对一 |
hasManyThrough |
远程一对多 |
belongsToMany |
多对多关联 |
morphMany |
多态一对多 |
morphOne |
多态一对一 |
morphTo |
多态关联 |
实例:
主表:tp_user
主键:id
附属表:tp_profile
字段:user_id
hobby
外键user_id
主表的主键与附属表的外键进行关联
一对一关联 hasOne
关联定义:
hasOne('关联模型类名','外键','主键')
关联模型:
外键:默认的外键规则是当前的模型名+
_id
主键:当前模型的主键,自动获取也可以指定
class UserModel extends Model
{
protected $table = 'tp_user'; public function profile()
{
return $this->hasOne(ProfileModel::class , 'user_id' , 'id'); }
}
class ProfileModel extends Model
{
protected $table = 'tp_profile';
}
$user = model\UserModel::find(19);
//return json($user->profile);
return $user->profile->hobby;
使用
save()
设置关联修改,通过主表修改附表字段的值$user = UserModel::find(19);
$user->profile->save(['hobby'=>'美女']);
->profile()
方法新增数据$user->profile()->save(['hobby'=>'靓女']);
相对关联(反向)
belongsTo('关联模型','外键','关联主键')
belonsTo
模式适合于附属表关联主表class ProfileModel extends Model
{
protected $table = 'tp_profile';
public function user()
{
return $this->belongsTo(UserModel::class , 'user_id' , id');
}
}
$profile = ProfileModel::find(1);
return $profile->user;
使用
hasOne()
模拟belongsTo()
$user = UserModel::hasWhere('profile',['id'=>19])->find();
// 这里的profile是user模型勒种的方法而不是profile模型类
$user = UserModel::hasWhere('profile',function($query){
$query->where('profile.id',19);
})-select();
一对多关联-hasMany
hasMany
模式适合主表关联附表,实现一对多查询;与一对一查询的主要区别就是,hasMany
可以实现查询返回多条。
hasMany('关联模型',['外键','主键']);
使用->profile()
方法模式,可以对数据进行筛选
$user->profile()->where('id','>',19)->select()
调用属性方式会直接返回结果,调用方法方式可以进行中间处理
使用has()
方法查询关联附表的主表内容
$user = UserModel::has('profile','>=',2)->select();
return $user;
这里的查询是在附表中判断数据与主表的关联内容
上述代码的主要功能:在附表中查找与主表有两次以上关联的数据,例如id=19在附表中两两条关联数据
使用haswhere
查询关联附表的处理内容(反向关联)
$user = UserModel::hasWhere('profile',['status'=>1])->select();
return $user;
$user = UserModel::hasWhere('profile',function($query){
$query->where('status','>=',1);
})->select();
使用save()/saveAll()
新增数据
$user = UserModel::find(20);
// 新增单条数据
$user->profile()->save(['hobby'=>'计算机','status'=>'1']);
// 新增批量数据
$user->profile()->saveAll([
['hobby'=>'计算机','status'=>'1'],
['hobby'=>'游戏机','status'=>'1']
]);
使用together()
删除主表内容时,附表关联的内容全部删除
$user = UserModel::with('profile')->find(20);
$user->together(['profile'])->delete();
关联预载入 with
普通的关联查询,会循环执行多次SQL查询;
$list = UserModel::select([19,20,21]);
foreach($list as $user)
{
dump($user->profile);
}
采用关联预载入的方式 ,可以减少多次查询的耗时;
with(['关联数据表1','关联数据表2']);
延迟预载入:先执行
select()
再执行load()
关联统计
使用withCount()
可以统计主表关联附表的个数,使用profile_count
$list = UserModel::withCount(['profile'])->select([19,20,21]);
foreacth($list as $user)
{
echo $user->profile_count;
}
关联统计的输出采用"[关联方法名]_count"的结构
同时支持withMax``withMin``withSum``withAvg
……
关联输出
使用hidden()
方法,隐藏主表字段或附表字段
$list = Usermodel::with('profile')->select();
return json($list->hidden(['profile.status']));
使用visible()
方法,只显示指定字段
使用append()
方法,添加额外的字段
多对多关联
三张表:
access表包含了user和role表的关联ID
belongsToMany('关联模型','中间表',['外键','关联键'])
关联模型:模型名或类名
中间表:{需要继承Pivot}
外键:
关联键:中间表的当前模型关联键名
参考官方文档
ThinkPHP6.0学习笔记-模型操作的更多相关文章
- ThinkPHP6.0学习笔记-验证器
验证器 By:Mirror王宇阳 验证器定义 验证器的使用,必须定义它:系统提供了一条命令直接生产一个验证器类: php think make:validate User 自动再应用目录下生成一个va ...
- 《TP5.0学习笔记---模型篇》
https://blog.csdn.net/self_realian/article/details/78596261 一.什么是模型 为什么我们要在项目中使用模型,其实我们知道,我们可以直接在控制器 ...
- DirectX 总结和DirectX 9.0 学习笔记
转自:http://www.cnblogs.com/graphics/archive/2009/11/25/1583682.html DirectX 总结 DDS DirectXDraw Surfac ...
- 一起学ASP.NET Core 2.0学习笔记(二): ef core2.0 及mysql provider 、Fluent API相关配置及迁移
不得不说微软的技术迭代还是很快的,上了微软的船就得跟着她走下去,前文一起学ASP.NET Core 2.0学习笔记(一): CentOS下 .net core2 sdk nginx.superviso ...
- Javascript学习笔记二——操作DOM
Javascript学习笔记 DOM操作: 一.GetElementById() ID在HTML是唯一的,getElementById()可以定位唯一的一个DOM节点 二.querySelector( ...
- MongoDB学习笔记:Python 操作MongoDB
MongoDB学习笔记:Python 操作MongoDB Pymongo 安装 安装pymongopip install pymongoPyMongo是驱动程序,使python程序能够使用Mong ...
- vue2.0学习笔记之路由(二)路由嵌套+动画
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- vue2.0学习笔记之路由(二)路由嵌套
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- hdcms v5.7.0学习笔记
hdcms v5.7.0学习笔记 https://note.youdao.com/ynoteshare1/index.html?id=c404d63ac910eb15a440452f73d6a6db& ...
随机推荐
- linux命令行界面如何安装图形化界面
linux命令行界面如何安装图形化界面 目录 问题描述 解决方案 安装包 测试是否安装成功 如何卸载图形化界面 遭遇问题 问题描述 当我们在安装Linux系统时,我们一开始可能安装的是非图形界面的系统 ...
- Lucene查询语法汇总
目录 一.单词查询 二.通配符查询 三.模糊查询 四.近似查询 五.范围查询 六.优先级查询 七.逻辑操作 八.括号分组 九.转义特殊字符 Lucene是目前最为流行的开源全文搜索引擎工具包,提供了完 ...
- ReentrantReadWriteLock 源码分析以及 AQS 共享锁 (二)
前言 上一篇讲解了 AQS 的独占锁部分(参看:ReentrantLock 源码分析以及 AQS (一)),这一篇将介绍 AQS 的共享锁,以及基于共享锁实现读写锁分离的 ReentrantReadW ...
- 学习webpack基础笔记01
学习webpack基础笔记 1.webpack搭建环境最重要的就是如何使用loader和plugins,使用yarn/npm安装插件.预处理器,正确的配置好去使用 2.从0配置webpack - 1. ...
- 通过js自动判断移动终端设备(ios\android等)
当用户用移动设备扫描一个二维码是,将扫描后的链接链接到一个页面,该页面只包含判断移动终端设备的js,判断好后自动跳转到对应的链接 或下载对应的内容. html代码如下: <script> ...
- 后端程序员必备:书写高质量SQL的30条建议
前言 本文将结合实例demo,阐述30条有关于优化SQL的建议,多数是实际开发中总结出来的,希望对大家有帮助. 1.查询SQL尽量不要使用select *,而是select具体字段. 反例子: sel ...
- 多线程的CAS
CAS Compare And Swap (Compare And Exchange) / 自旋 / 自旋锁 / 无锁 独占锁:独占锁是一种悲观锁,synchronized就是一种独占锁,会导致其它所 ...
- 深度学习归一化:BN、GN与FRN
在深度学习中,使用归一化层成为了很多网络的标配.最近,研究了不同的归一化层,如BN,GN和FRN.接下来,介绍一下这三种归一化算法. BN层 BN层是由谷歌提出的,其相关论文为<Batch No ...
- 从零开始学习R语言(八)——R语言绘图
本文首发于知乎专栏:https://zhuanlan.zhihu.com/p/74051739 也同步更新于我的个人博客:https://www.cnblogs.com/nickwu/p/125683 ...
- JS事件流模型
JS事件流模型 事件捕获Event Capturing是一种从上而下的传播方式,以click事件为例,其会从最外层根节向内传播到达点击的节点,为从最外层节点逐渐向内传播直到目标节点的方式. 事件冒泡E ...