Laravel Eloquent 数据库关联模型的增删改操作

Laravel Eloquent ORM 提供了数据模型关联表操作的 API,熟练掌握这些API后,才体会到 Laravel 数据库操作有多高效。

一、hasMany 一对多关联

save/saveMany 创建关联记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 新建一条数据 Post 的评论,save 将自动添加 post_id 字段
$comment = new Comment(['message' => 'A new comment.']);
$post = Post::find(1);
$post->comments()->save($comment);

// 保持多条记录
$post->comments()->saveMany([
new Comment(['message' => 'A new comment.']),
new Comment(['message' => 'Another new comment.']),
]);

// 更新后需要重新加载模型及其关联,才会加到 $post->comments 中
$post->refresh();

// 所有评论,包括新保存的评论...
$post->comments;

create/createMany 创建关联记录

save/saveMany 的区别是参数时数组,而不是模型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use App\Models\Post;

$post = Post::find(1);

$comment = $post->comments()->create([
'message' => 'A new comment.',
]);

$post = Post::find(1);

$post->comments()->createMany([
['message' => 'A new comment.'],
['message' => 'Another new comment.'],
]);

push 递归保存模型和关联数据

保持模型同时,保存其关联数据。

例:保存 Post 模型及其评论和评论作者

1
2
3
4
5
6
$post = Post::find(1);

$post->comments[0]->message = 'Message';
$post->comments[0]->author->name = 'Author Name';

$post->push();

二、Belongs To (一对多反向)属于关联

1
2
3
4
5
6
7
8
9
10
11
12
use App\Models\Account;

$account = Account::find(10);

// associate 将子模型分配给新的父模型
$user->account()->associate($account);

// dissociate 从子模型中删除父模型,将关联外键设置为 null
$user->account()->dissociate();

$user->save();

三、多对多关联

attach 创建多对多关联记录

用于新建时。

1
2
3
4
5
6
7
8
9
10
// 创建多对多关联记录
$user->roles()->attach($roleId);
$user->roles()->attach([1, 2, 3]);
// 可以附加中间表字段数据
$user->roles()->attach($roleId, ['expires' => $expires]);
$user->roles()->attach([1 => ['expires' => $expires], 2, 3]);
$user->roles()->attach([
1 => ['expires' => $expires],
2 => ['expires' => $expires],
]);

detach 删除中间表关联记录

用于删除时。

1
2
3
4
5
6
7
8
// 移除用户的一个角色...
$user->roles()->detach($roleId);

// 移除用户的多个角色
$user->roles()->detach([1, 2, 3]);

// 移除用户的所有角色...
$user->roles()->detach();

sync 同步关联

用于修改模型时。

中间表记录中,所有未在 ID 数组中的记录都将会被移除,在数组中的可更新。

1
2
3
4
5
6
7
8
9
$user->roles()->sync([1, 2, 3]);
$user->roles()->sync([1 => ['expires' => true], 2, 3]);


// $user->roles()->syncWithPivotValues([1 => ['active' => true], 2 => ['active' => true], 3 => ['active' => true]]) 的简写
$user->roles()->syncWithPivotValues([1, 2, 3], ['active' => true]);

// 同步但不移除现有的关联 ID
$user->roles()->syncWithoutDetaching([1, 2, 3]);

toggle 切换关联

关联表中有则删除,无则新建。

1
$user->roles()->toggle([1, 2, 3]);

四、更新父级时间戳

当一个模型属 belongsTo 或者 belongsToMany 另一个模型时, 例如 Comment 属于 Post ,当 Comment 模型被更新时,你需要自动「触发」父级 Post 模型的 updated_at 时间戳的更新。Eloquent 让它变得简单,只要在子模型加一个包含关联名称的 touches 属性即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Comment extends Model
{
/**
* 需要触发的所有关联关系。
*/
protected $touches = ['post'];

/**
* 评论所属文章。
*/
public function post()
{
return $this->belongsTo(Post::class);
}
}

参考

Laravel 9 中文文档

Laravel Eloquent 数据库关联模型的增删改操作

https://coderpan.com/php/laravel-eloquent-pivot-read-write.html

作者

CoderPan

发布于

2023-02-12

更新于

2024-07-18

许可协议

评论