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数组的namescore数据。


最佳操作实践

新增操作:

新增数据的最佳实践原则:使用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字段的数据,因此可以很好的避免表单的非法查询条件传入,在这个示例中仅能使用namecreate_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_timeupdate_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部分


模型软删除

在实际项目中,对数据频繁使用删除操作会导致性能问题,软删除的作用就是把数据加上删除标,而不是真正的删除,同时也便于需要的时候进行数据的恢复。

要使用软删除功能,需要引入SoftDeletetrait,例如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学习笔记-模型操作的更多相关文章

  1. ThinkPHP6.0学习笔记-验证器

    验证器 By:Mirror王宇阳 验证器定义 验证器的使用,必须定义它:系统提供了一条命令直接生产一个验证器类: php think make:validate User 自动再应用目录下生成一个va ...

  2. 《TP5.0学习笔记---模型篇》

    https://blog.csdn.net/self_realian/article/details/78596261 一.什么是模型 为什么我们要在项目中使用模型,其实我们知道,我们可以直接在控制器 ...

  3. DirectX 总结和DirectX 9.0 学习笔记

    转自:http://www.cnblogs.com/graphics/archive/2009/11/25/1583682.html DirectX 总结 DDS DirectXDraw Surfac ...

  4. 一起学ASP.NET Core 2.0学习笔记(二): ef core2.0 及mysql provider 、Fluent API相关配置及迁移

    不得不说微软的技术迭代还是很快的,上了微软的船就得跟着她走下去,前文一起学ASP.NET Core 2.0学习笔记(一): CentOS下 .net core2 sdk nginx.superviso ...

  5. Javascript学习笔记二——操作DOM

    Javascript学习笔记 DOM操作: 一.GetElementById() ID在HTML是唯一的,getElementById()可以定位唯一的一个DOM节点 二.querySelector( ...

  6. MongoDB学习笔记:Python 操作MongoDB

    MongoDB学习笔记:Python 操作MongoDB   Pymongo 安装 安装pymongopip install pymongoPyMongo是驱动程序,使python程序能够使用Mong ...

  7. vue2.0学习笔记之路由(二)路由嵌套+动画

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  8. vue2.0学习笔记之路由(二)路由嵌套

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. hdcms v5.7.0学习笔记

    hdcms v5.7.0学习笔记 https://note.youdao.com/ynoteshare1/index.html?id=c404d63ac910eb15a440452f73d6a6db& ...

随机推荐

  1. linux命令行界面如何安装图形化界面

    linux命令行界面如何安装图形化界面 目录 问题描述 解决方案 安装包 测试是否安装成功 如何卸载图形化界面 遭遇问题 问题描述 当我们在安装Linux系统时,我们一开始可能安装的是非图形界面的系统 ...

  2. Lucene查询语法汇总

    目录 一.单词查询 二.通配符查询 三.模糊查询 四.近似查询 五.范围查询 六.优先级查询 七.逻辑操作 八.括号分组 九.转义特殊字符 Lucene是目前最为流行的开源全文搜索引擎工具包,提供了完 ...

  3. ReentrantReadWriteLock 源码分析以及 AQS 共享锁 (二)

    前言 上一篇讲解了 AQS 的独占锁部分(参看:ReentrantLock 源码分析以及 AQS (一)),这一篇将介绍 AQS 的共享锁,以及基于共享锁实现读写锁分离的 ReentrantReadW ...

  4. 学习webpack基础笔记01

    学习webpack基础笔记 1.webpack搭建环境最重要的就是如何使用loader和plugins,使用yarn/npm安装插件.预处理器,正确的配置好去使用 2.从0配置webpack - 1. ...

  5. 通过js自动判断移动终端设备(ios\android等)

    当用户用移动设备扫描一个二维码是,将扫描后的链接链接到一个页面,该页面只包含判断移动终端设备的js,判断好后自动跳转到对应的链接 或下载对应的内容. html代码如下: <script> ...

  6. 后端程序员必备:书写高质量SQL的30条建议

    前言 本文将结合实例demo,阐述30条有关于优化SQL的建议,多数是实际开发中总结出来的,希望对大家有帮助. 1.查询SQL尽量不要使用select *,而是select具体字段. 反例子: sel ...

  7. 多线程的CAS

    CAS Compare And Swap (Compare And Exchange) / 自旋 / 自旋锁 / 无锁 独占锁:独占锁是一种悲观锁,synchronized就是一种独占锁,会导致其它所 ...

  8. 深度学习归一化:BN、GN与FRN

    在深度学习中,使用归一化层成为了很多网络的标配.最近,研究了不同的归一化层,如BN,GN和FRN.接下来,介绍一下这三种归一化算法. BN层 BN层是由谷歌提出的,其相关论文为<Batch No ...

  9. 从零开始学习R语言(八)——R语言绘图

    本文首发于知乎专栏:https://zhuanlan.zhihu.com/p/74051739 也同步更新于我的个人博客:https://www.cnblogs.com/nickwu/p/125683 ...

  10. JS事件流模型

    JS事件流模型 事件捕获Event Capturing是一种从上而下的传播方式,以click事件为例,其会从最外层根节向内传播到达点击的节点,为从最外层节点逐渐向内传播直到目标节点的方式. 事件冒泡E ...