JSON字段
数据库JSON
- 数据库写入JSON字段,直接通过数组的方式即可完成;
$data = [
'username' => '辉夜',
'password' => '123',
'gender' => '女',
'email' => 'huiye@163.com',
'price' => 90,
'details' => '123',
'uid' => 1011,
'status' => 1,
'list' => ['username'=>'辉夜', 'gender'=>'女','email'=>'huiye@163.com'],
];
Db::name('user')->json(['list'])->insert($data);
- 如果要查询数据时,正确转换json数据格式,也需要设置json方法;
Db::name('user')->json(['list'])->find(278);
- 如果要将json字段里的数据作为查询条件,可以通过如下方式实现:
$user = Db::name('user')->json(['list'])->where('list->username', '辉夜')->find();
- 如果想完全修改json数据,可以使用如下的方式实现:
$data['list'] = ['username'=>'李白', 'gender'=>'男', 'email'=>'libai@163.com'];
Db::name('user')->json(['list'])->where('id', 278)->update($data);
- 如果只想修改json数据里的某一个项目,可以使用如下的方式实现:
$data['list->username'] = '李黑';
Db::name('user')->json(['list'])->where('id', 278)->update($data);
模型JSON
- 想要写入json字段的字符字段,需要设置;
protected $json = ['list'];
- 使用模型方式去新增包含json数据的字段;
$user = new UserModel();
$user->username = '李白';
$user->password = '123';
$user->gender = '男';
$user->email = 'libai@163.com';
$user->price = 100;
$user->uid = 1011;
$user->status = 1;
$user->details = 123;
$user->list = ['username'=>'辉夜', 'gender'=>'女','email'=>'huiye@163.com'];
$user->save();
- 也可以通过对象的方式,进行对json字段的写入操作;
$list = new \StdClass();
$list->username = '辉夜';
$list->gender = '女';
$list->email = 'huiye@163.com';
$list->uid = 1011;
$user->list = $list;
- 通过对象调用方式,直接获取json里面的数据;
$user = UserModel::find(278);
return $user->list->username;
- 通过json的数据查询,获取一条数据;
$user = UserModel::where('list->username', '辉夜')->find();
return $user->list->email;
- 更新修改json数据,直接通过对象方式即可;
$user = UserModel::find(278);
$user->list->username = '李白';
$user->save();
模型的软删除
模型软删除
- 介于数据库软删除没有太多的可操作的方法,官方手册推荐使用模型软操作;
- 首先,需要在模型端设置软删除的功能,引入
SoftDelete
,它是trait
;
use SoftDelete;
protected $deleteTime = 'delete_time';
delete_time
默认我们设置的是null
,如果你想更改这个默认值,可以设置:
//protected $defaultSoftDelete = 0;
- 软删除和方法如下,包括
destroy()
和delete()
:
UserModel::destroy(289);
UserModel::find(287)->delete();
- 默认情况下,开启了软删除功能的查询,模型会自动屏蔽被软删除的数据;
$user = UserModel::select();
return json($user);
- 在开启软删除功能的前提下,使用
withTrashed()
方法取消屏蔽软删除的数据;
$user = UserModel::withTrashed()->select();
return json($user);
- 如果只想查询被软删除的数据,使用
onlyTrashed()
方法即可;
$user = UserModel::onlyTrashed()->select();
return json($user);
- 如果想让某一条被软删除的数据恢复到正常数据,可以使用
restore()
方法;
$user = UserModel::onlyTrashed()->find();
$user->restore();
- 如果想让一条软删除的数据真正删除,在恢复正常后,使用
force()
和delete()
;
$user = UserModel::onlyTrashed()->find(193);
$user->restore();
$user->force()->delete(); //或 UserModel::destroy(288, true)
模型和数据库的事件
数据库事件
- 当你执行增删改查的时候,可以触发一些事件来执行额外的操作;
- 这些额外的操作事件,可以部署在构造方法里等待激活执行;
- 数据库事件方法为
Db::event('事件名', '执行函数')
,具体事件名如下:
- 数据库事件只支持:
find
,select
,update
,delete
,insert
这几个方法; - 在控制器端,事件一般可以写在初始化方法里,方便统一管理;
public function initialize()
{
Db::event('before_select', function ($query) {
echo '执行了批量查询操作!';
});
Db::event('after_update', function ($query) {
echo '执行了修改操作!';
});
}
模型事件
- 支持的事件类型更加的丰富,具体如下:
- 在模型端使用静态方法调用即可完成事件触发;
protected static function onAfterRead($query)
{
echo '执行了查询方法';
}
protected static function onBeforeUpdate($query)
{
echo '准备修改中...';
}
protected static function onAfterUpdate($query)
{
echo '修改完毕...';
}
关联模型初探
关联模型定义
- 关联模型,顾名思义,就是将表与表之间进行关联和对象化,更高效的操作数据;
- 我们已经有了一张
tp_user
表,主键为id
;我们需要一个附属表,来进行关联; - 附属表
tp_profile
,建立两个字段user_id
和hobby
,外键是user_id
; - 创建
User
模型和Profile
模型,均为空模型; User
模型端,需要关联Profile
,具体方式如下:
class User extends Model
{
public function profile()
{
//hasOne 表示一对一关联,参数一表示附表,参数二外键,默认 user_id
return $this->hasOne(Profile::class,'user_id');
}
}
- 创建一个控制器用于测试输出;
$user = UserModel::find(21);
return json($user->profile);
return $user->profile->hobby;
- 对于关联方式,系统提供了9种方案,具体如下:
- 上面的例子,我们采用了一对一的关联模型,它还有相对的反向关联;
class Profile extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
}
- 正反向关联也就是关联关系和相对的关联关系,具体如下表:
一对一关联查询
hasOne模式
hasOne
模式,适合主表关联附表,具体设置方式如下:
hasOne('关联模型','外键','主键');
return $this->hasOne(Profile::class,'user_id','id');
- 关联模型(必须):关联的模型名或者类名
- 外键:默认的外键规则是,
当前模型名_id
(不含命名空间),例如user_id
- 主键:当前模型主键,默认会自动获取也可以指定传入
- 在上一节课,我们了解了表与表关联后,实现的查询方案;
$user = UserModel::find(21);
return $user->profile->hobby;
- 使用
save()
方法,可以设置关联修改,通过主表修改附表字段的值;
$user = UserModel::find(19);
$user->profile->save(['hobby'=>'酷爱小姐姐']);
->profile
属性方式可以修改数据,->profile()
方法方式可以新增数据;
$user->profile()->save(['hobby'=>'不喜欢吃青椒']);
belongsTo模式
- belongsTo 模式,适合附表关联主表,具体设置方式如下:
belongsTo('关联模型','外键','关联主键');
return $this->belongsTo(Profile::class,'user_id', 'id');
- 关联模型(必须):模型名或者模型类名
- 外键:当前模型外键,默认的外键名规则是
关联模型模型名_id
(不含命名空间) - 关联主键:关联模型主键,一般会自动获取也可以指定传入
- 对于
belongsTo()
的查询方案,上一节课已经了解过,如下:
$profile = ProfileModel::find(1);
return $profile->user->email;
- 使用
hasOne()
也能模拟belongsTo()
来进行查询;
//参数一表示的是 User 模型类的 profile 方法,而非 Profile 模型类
$user = UserModel::hasWhere('profile', ['id'=>2])->find();
return json($user);
//采用闭包,这里是两张表操作,会导致 id 识别模糊,需要指明表
$user = UserModel::hasWhere('profile', function ($query) {
$query->where('id', 2);
})->select();
return json($user);
一对多关联查询
hasMany 模式
hasMany
模式,适合主表关联附表,实现一对多查询,具体设置方式如下:
hasMany('关联模型','外键','主键');
return $this->hasMany(Profile::class,'user_id', 'id');
- 关联模型(必须):模型名或者模型类名
- 外键:关联模型外键,默认的外键名规则是
当前模型名_id
- 主键:当前模型主键,一般会自动获取也可以指定传入
- 在上一节课,我们了解了表与表关联后,实现的查询方案;
$user = UserModel::find(19);
return json($user->profile);
- 使用
->profile()
方法模式,可以进一步进行数据的筛选;
$user->profile()->where('id', '>', 10)->select();
$user->profile->where('id', '>', 10);
- 使用
has()
方法,查询关联附表的主表内容,比如大于等于2条的主表记录;
UserModel::has('profile', '>=', 2)->select();
- 使用
hasWhere()
方法,查询关联附表筛选后记录,比如兴趣审核通过的主表记录;
UserModel::hasWhere('profile', ['status'=>1])->select();
- 使用
save()
和saveAll()
进行关联新增和批量关联新增,方法如下:
$user = UserModel::find(19);
$user->profile()->save(['hobby'=>'测试喜好', 'status'=>1]);
$user->profile()->saveAll([
['hobby'=>'测试喜好', 'status'=>1],
['hobby'=>'测试喜好', 'status'=>1]
]);
- 使用
together()
方法,可以删除主表内容时,将附表关联的内容全部删除;
- 该操作为事务操作,表引擎必须为
InnoDB
,否则会出现以下报错 SQLSTATE[HY000]: General error: 1785 Statement violates GTID consistency: Updates to non-transactional tables can only be done in either autocommitted statements or single-statement transactions, and never in the same statement as updates to transactional tables.
$user = UserModel::with('profile')->find(227);
$user->together(['profile'])->delete();
关联预载入
关联预载入
- 在普通的关联查询下,我们循环数据列表会执行n+1次SQL查询;
$list = UserModel::select([19, 20, 21]);
foreach ($list as $user) {
dump($user->profile);
}
- 上面继续采用一对一的构建方式,打开
trace
调试工具,会得到四次查询; - 如果采用关联预载入的方式,将会减少到两次,也就是起步一次,循环一次;
$list = UserModel::with(['profile'])->select([19, 20, 21]);
foreach ($list as $user) {
dump($user->profile);
}
- 关联预载入减少了查询次数提高了性能,但是不支持多次调用;
- 如果你有主表关联了多个附表,都想要进行预载入,可以传入多个模型方法即可;
- 为此,我们再创建一张表
tp_book
,和tp_profile
一样,关联tp_user
;
$list = UserModel::with(['profile','book'])->select([19, 20, 21]);
foreach ($list as $user) {
dump($user->profile.$user->book);
}
- 如果想要在关联模型实现链式操作,可以使用闭包,比如添加
->field()
;
$list = UserModel::field('id,username')->with(['profile'=>function ($query) {
$query->field('user_id, hobby');
}])->select([19,20,21]);
- 关联预载入还提供了一个延迟预载入,就是先执行
select()
再load()
载入;
$list = UserModel::select([19, 20, 21]);
$list->load(['profile']);
foreach ($list as $user) {
dump($user->profile);
}
关联统计和输出
关联统计
- 使用
withCount()
方法,可以统计主表关联附表的个数,输出用profile_count
;
$list = UserModel::withCount(['profile'])->select([19,20,21]);
foreach ($list as $user) {
echo $user->profile_count;
}
- 关联统计的输出采用
关联方法名_count
,这种结构输出; - 不单单支持
Count
,还有如下统计方法,均可支持; withMax()
,withMin()
,withSum()
,withAvg()
等;- 除了
withCount()
不需要指定字段,其它均需要指定统计字段;
$list = UserModel::withSum(['profile'], 'status')->select([19,20,21]);
foreach ($list as $user) {
echo $user->profile_sum.'<br>';
}
- 对于输出的属性,可以自定义:
$list = UserModel::withSum(['profile'=>'p_s'], 'status')->select([19,20,21]);
foreach ($list as $user) {
echo $user->p_s.'<br>';
}
关联输出
- 使用
hidden()
方法,隐藏主表字段或附属表的字段;
$list = UserModel::with('profile')->select();
// return json($list->hidden(['profile.status']));
return json($list->hidden(['username','password','profile'=>['status','id']]));
- 使用
visible()
方法,只显示相关的字段;
$list->visible(['profile.status']);
- 使用
append()
方法,添加一个额外字段,比如另一个关联的对象模型;
$list->append(['book']);
多对多关联查询
多对多关联
- 复习一下一对一,一个用户对应一个用户档案资料,是一对一关联;
- 复习一下一对多,一篇文章对应多个评论,是一对多关联;
- 多对多怎么理解,分解来看,一个用户对应多个角色,而一个角色对应多个用户;
- 那么这种对应关系,就是多对多关系,最经典的应用就是权限控制;
- 首先,我们来看多对多关系的三张表,具体如下:
- tp_user:用户表;tp_role:角色表;tp_access:中间表;
access
表包含了user
和role
表的关联id
,多对多模式;- 在
User.php
的模型中,设置多对多关联,方法如下:
public function roles()
{
return $this->belongsToMany(Role::class, Access::class);
}
- 在
roles
方法中,belongsToMany
为多对多关联,具体参数如下:
belongsToMany('关联模型','中间表','外键','关联键');
$this->belongsToMany(Role::class, Access::class, 'role_id', 'user_id');
Role.php
和Access.php
创建一个空模型即可,无须创建任何;- 注意:
Role
继承Model
即可,而中间表需要继承Pivot
; - 测试查询方式如下:
//得到一个用户:蜡笔小新
$user = UserModel::find(21);
//获取这个用户的所有角色
$roles = $user->roles;
//输出这个角色所具有的权限
return json($roles);
- 当我们要给一个用户创建一个角色时,用到多对多关联新增;
- 而关联新增后,不但会给
tp_role
新增一条数据,也会给tp_access
新增一条;
$user->roles()->save(['type'=>'测试管理员']);
// $user->roles()->saveAll([[...],[...]]);
- 一般来说,上面的这种新增方式,用于初始化角色比较合适;
- 也就是说,各种权限的角色,并不需要再新增了,都是初始制定好的;
- 那么,我们真正需要就是通过用户表新增到中间表关联即可;
$user->roles()->save(1);
$user->roles()->save(Role::find(1));
$user->roles()->saveAll([1,2,3]);
$user->roles()->attach(1);
$user->roles()->attach(2, ['details'=>'测试详情']);
- 除了新增,还有直接删除中间表数据的方法:
$user->roles()->detach(2);
最后一次更新于2020-07-30 16:53
0 条评论