作者:拾年之璐 公众号:知行研究院
13.1 关联新增
1、比如有一个功能:给一个用户增加关联的书籍。则方法如下。
首先观察book表,没有时间字段,需要取消自动写入时间
。同时,也要为book表设置取消批量赋值
:
//取消批量赋值
protected $guarded = [];
//取消自动时间字段
public $timestamps = false;
然后在控制类中写入:
//先限定用户
$user = User::find(19);
//给这个用户关联的book 新增一条记录
//user_id 会自动写入19,title 自定义
$user->book()->save(new Book(['title' => '《哈利波特》']));
然后运行,其执行的SQL为:
select * from `laravel_users` where `laravel_users`.`id` = 19 limit 1
insert into `laravel_books` (`title`, `user_id`) values ('《哈利波特》', 19)
当然,也可以批量新增:
//先限定用户
$user = User::find(19);
//批量新增
$user->book()->saveMany([
new Book(['title' => '《哈利波特》']),
new Book(['title' => '《指环王》'])
]);
其执行的SQL为:
select * from `laravel_users` where `laravel_users`.`id` = 19 limit 1
insert into `laravel_books` (`title`, `user_id`) values ('《哈利波特》', 19)
insert into `laravel_books` (`title`, `user_id`) values ('《指环王》', 19)
2、create
和 createMany
只需要插入数组即可完成关联新增;
比如:
//先限定用户
$user = User::find(19);
//关联插入
$user->book()->create([
'title' => '《哈利波特》'
]);
再如:
//先限定用户
$user = User::find(19);
//关联批量插入
$user->book()->createMany([
['title' => '《哈利波特》'],
['title' => '《指环王》']
]);
其执行结果和上面一致。
3、此外,还有:findOrNew
、firstOrNew
、firstOrCreate
和 updateOrCreate
方法;
findOrNew:Find a model by its primary key or return new instance of the related model.
firstOrNew:Get the first related model record matching the attributes or instantiate it.
firstOrCreate:Get the first related record matching the attributes or create it.
updateOrCreate:Create or update a related record matching the attributes, and fill it with values.
比如:
//先限定用户
$user = User::find(19);
return $user->book()->firstOrNew([
'title' => '《哈利波特》'
]);
这种方式,如果能找到与title相关的数据,则返回该数据,如果没有找到,则生成一个模型(非数据库插入),再返回该模型,是临时的
。
再如:
//先限定用户
$user = User::find(19);
return $user->book()->firstOrCreate([
'title' => '《哈利波特》'
]);
这种方式,如果能找到与title相关的数据,则返回该数据,如果没有找到,则在数据库中插入该数据,然后再返回插入的这条数据。
13.2 关联删除
使用 delete()
进行关联删除。如:
//关联删除,删除user_id=19 的书
$user = User::find(19);
$user->book()->delete();
执行的SQL为:
select * from `laravel_users` where `laravel_users`.`id` = 19 limit 1
delete from `laravel_books` where `laravel_books`.`user_id` = 19 and `laravel_books`.`user_id` is not null
13.3 关联修改
1、使用 update()
方法进行关联修改。如:
//关联修改,修改 user_id=19 的书
$user = User::find(19);
$user->book()->update(['title' => '《修改书籍》']);
执行的SQL为:
select * from `laravel_users` where `laravel_users`.`id` = 19 limit 1
update `laravel_books` set `title` = '《修改书籍》' where `laravel_books`.`user_id` = 19 and `laravel_books`.`user_id` is not null
2、使用 associate()
方法来修改掉书籍关联的用户,即修改user_id:
//修改关联的外键,即:user_id 修改,换用户
$user = User::find(20);
$book = Book::find(9);
$book->user()->associate($user);
$book->save();
执行的SQL为:
select * from `laravel_users` where `laravel_users`.`id` = 20 limit 1
select * from `laravel_books` where `laravel_books`.`id` = 9 limit 1
update `laravel_books` set `user_id` = 20 where `id` = 9
另外,如果想取消一本书的拥有者,比如将 user_id 设置为null,字段要设置可以null;
$book = Book::find(8);
$book->user()->dissociate();
$book->save();
执行的SQL为:
select * from `laravel_books` where `laravel_books`.`id` = 8 limit 1
update `laravel_books` set `user_id` = '' where `id` = 8
3、在搜索书籍的对应用户的时候,空null 字段会导致用户出现null 数据;我们可以采用空对象默认模型的方式,去解决这个问题;
在Book模型中,为关联的代码,追加写入 withDefault()
方法,如下所示:
//Book.php
public function user()
{
return $this->belongsTo(User::class, 'user_id', 'id')
->withDefault([
'id' => 0,
'username' => '游客用户'
]);
}
13.4 多对多关联的增删改
增删改的都是中间表。
1、多对多的新增:比如,给用户增加一个角色权限,具体如下:
//得到要添加权限的用户
$user = User::find(99);
//得到权限的id,比如超级管理员
$roleId = 1;
//给辉夜设置成超级管理员
$user->role()->attach($roleId);
执行的SQL为:
select * from `laravel_users` where `laravel_users`.`id` = 99 limit 1
insert into `laravel_role_users` (`role_id`, `user_id`) values (1, 99)
2、如果你想给中间表附加details 字段的数据,可以使用第二参数;
//得到要添加权限的用户
$user = User::find(99);
//得到权限的id,比如超级管理员
$roleId = 1;
//给辉夜设置成超级管理员
///$user->role()->attach($roleId);
$user->role()->attach($roleId, ['details' => '喀']); //第二参数
执行的SQL为:
select * from `laravel_users` where `laravel_users`.`id` = 99 limit 1
insert into `laravel_role_users` (`details`, `role_id`, `user_id`) values ('喀', 1, 99)
3、如果想移出某个用户的角色权限,可以使用detach()方法;
//权限的用户
$user = User::find(99);
//权限的id,比如超级管理员
$roleId = 1;
//删除一个角色权限
$user->role()->detach($roleId);
执行的SQL为:
select * from `laravel_users` where `laravel_users`.`id` = 99 limit 1
delete from `laravel_role_users` and `user_id` = 99 and `role_id` in (1)
如果不指定中间表id($roleId),那么就移出这个用户的所有权限角色;
4、也支持批量处理,直接用数组传递参数即可;
//这里传递的是角色权限表的ID
$user->role()->attach([1,2,3]); //附加值:1 => ['detail' => 'xxx']
//删除指定的user_id
$user->role()->detach([1,2,3]);
如:
//权限的用户
$user = User::find(99);
//这里传递的是角色权限表的ID
$user->role()->attach([1 => ['details' => '11111'], 2 => ['details' => '222222'], 3 => ['details' => '333333']]);
执行的SQL为:
select * from `laravel_users` where `laravel_users`.`id` = 99 limit 1
insert into `laravel_role_users` (`details`, `role_id`, `user_id`) values ('11111', 1, 99), ('222222', 2, 99), ('333333', 3, 99)
再如:
//权限的用户
$user = User::find(99);
//删除指定的user_id
$user->role()->detach([1,2,3]);
执行的SQL为:
select * from `laravel_users` where `laravel_users`.`id` = 99 limit 1
delete from `laravel_role_users` where `user_id` = 99 and `role_id` in (1, 2, 3)
5、使用sync()方法,可以新增角色权限,且可以判断已存在而不再新增;
//同步关联,已存在不再新增
return $user->role()->sync([1,2,3]); //附加值:1 => ['detail' => 'xxx']
比如:
//权限的用户
$user = User::find(99);
//同步关联,已存在不再新增
return $user->role()->sync([1,2,3]);
第一次执行的SQL为:
select * from `laravel_users` where `laravel_users`.`id` = 99 limit 1
select * from `laravel_role_users` where `user_id` = 99
insert into `laravel_role_users` (`role_id`, `user_id`) values (1, 99)
insert into `laravel_role_users` (`role_id`, `user_id`) values (2, 99)
insert into `laravel_role_users` (`role_id`, `user_id`) values (3, 99)
然后再执行一次,执行的SQL为:
select * from `laravel_users` where `laravel_users`.`id` = 99 limit 1
select * from `laravel_role_users` where `user_id` = 99
这里是因为判断已经存在了,就无需新增了。
接下来,修改代码为:
//权限的用户
$user = User::find(99);
//同步关联,已存在不再新增
return $user->role()->sync([1,2,4]);//最后一个改为4
然后再执行,其 SQL 为:
select * from `laravel_users` where `laravel_users`.`id` = 99 limit 1
select * from `laravel_role_users` where `user_id` = 99
delete from `laravel_role_users` where `user_id` = 99 and `role_id` in (3)
insert into `laravel_role_users` (`role_id`, `user_id`) values (4, 99)
这里注意,把已经存在的 3 删除了。
6、使用 udpateExistingPivot()
可更新指定 roleId
的额外字段;
//更新中间表的额外字段
$user->role()->updateExistingPivot($roleId, ['details'=>'喀']);
如:
//权限的用户
$user = User::find(99);
$roleId = 1;
//更新中间表的额外字段
$user->role()->updateExistingPivot($roleId, ['details'=>'哈哈哈']);
其执行的SQL为:
select * from `laravel_users` where `laravel_users`.`id` = 99 limit 1
update `laravel_role_users` set `details` = '哈哈哈' where `user_id` = 99 and `role_id` in (1)
直接使用update()是更新所有;
如:
//权限的用户
$user = User::find(99);
//更新中间表的额外字段
$user->role()->update(['details'=>'呵呵呵']);
其执行的SQL为:
select * from `laravel_users` where `laravel_users`.`id` = 99 limit 1
update `laravel_roles` inner join `laravel_role_users` on `laravel_roles`.`id` = `laravel_role_users`.`role_id` set `details` = '呵呵呵' where `laravel_role_users`.`user_id` = 99
然后数据库中,所有user_id=99的记录的details字段,全部修改为 呵呵呵。
另:通过查看源码或IDE 代码提示的方法,有更多的操作;可自行阅读扩展。
以上。