由于 Illuminate\Queue\SerializesAndRestoresModelIdentifiers,Job 类内部的加载关系发生了变化
Posted
技术标签:
【中文标题】由于 Illuminate\\Queue\\SerializesAndRestoresModelIdentifiers,Job 类内部的加载关系发生了变化【英文标题】:Loaded relationship changes inside Job class because of Illuminate\Queue\SerializesAndRestoresModelIdentifiers由于 Illuminate\Queue\SerializesAndRestoresModelIdentifiers,Job 类内部的加载关系发生了变化 【发布时间】:2021-06-21 17:40:38 【问题描述】:我有一个接受User
的工作类。我使用闭包在构造函数内的该模型中加载hasMany
关系。不知何故,结果发生了变化,就好像闭包在到达 handle
方法时被丢弃了一样。
类似这样的:
class SomeJob implements ShouldQueue
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected User $user;
public function __construct(User $user)
// load children relationship where field = 3
$this->user = tap($user)->load([
'children' => function ($children)
$children->where('field', 3);
]);
dump($this->user->children->toArray());
public function handle()
dump($this->user->children->toArray());
使用同步队列驱动程序,我创建了一个路由来调度此作业并在浏览器中检查结果。转储的结果不同。
根据 laravel 调试栏,关系查询在 \vendor\laravel\framework\src\Illuminate\Queue\SerializesAndRestoresModelIdentifiers.php:102
内部重复,但没有闭包。
query | location |
---|---|
select * from "users" where "users"."id" = 6 and "users"."deleted_at" is null limit 1 | \vendor\laravel\framework\src\Illuminate\Support\Traits\ForwardsCalls.php:23 |
select * from "children" where "children"."usuario_id" in (6) and "field" = 3 and "children"."deleted_at" is null | \app\Jobs\SomeJob.php:30 |
select * from "users" where "users"."id" = 6 limit 1 | \vendor\laravel\framework\src\Illuminate\Queue\SerializesAndRestoresModelIdentifiers.php:102 |
select * from "children" where "children"."usuario_id" in (6) and "children"."deleted_at" is null | \vendor\laravel\framework\src\Illuminate\Queue\SerializesAndRestoresModelIdentifiers.php:102 |
这是正常行为吗?
【问题讨论】:
在 tap($user) 中使用 tap() 助手的原因是什么。不,直接 $user->load(...) 您能在用户模型中粘贴子关系定义吗? 为什么不直接在handle方法中做呢? tap() 的原因基本上是花哨的,并且在一个衬里中完成。相当于做$this->user = $user; $this->user->load('children');
@lagbox 没有真正的原因。我很惊讶地发现这种奇怪的行为
【参考方案1】:
作业中的构造函数与通常的类构造函数不同。 SerializesModels 使用它来序列化和反序列化传递的模型,但我认为您的点击并没有真正执行(数据未序列化时的同步驱动程序除外)
这就是为什么你的 handle 方法会加载用户和所有相关的孩子而不是过滤。
你需要移动子加载来处理方法
public function handle()
$this->user->load([
'children' => function ($children)
$children->where('field', 3);
]);
【讨论】:
点击在构造函数中正确执行。构造函数中转储的数据是我所期望的,并且查询显示在查询日志中。我知道我可以在句柄方法中加载关系,但我真正不明白的是为什么模型序列化没有考虑加载闭包。这才是我真正想知道的。【参考方案2】:当模型以这种方式序列化时,只使用一个“标识符”。它实际上并没有像serialize
那样序列化模型。这就是为什么它必须在反序列化时查询模型,因为只有一个标识符才能再次找到模型。
它知道在反序列化后加载关系,因为该信息与模型的标识符一起保存,但它只是加载了什么关系,而不是加载方式或当前在其中的内容。因此,它将加载先前通过简单调用 load
加载的关系,并在未序列化时使用关系名称。
打开该特征SerializesAndRestoresModelIdentifiers
,您将看到它是如何做到的。
【讨论】:
以上是关于由于 Illuminate\Queue\SerializesAndRestoresModelIdentifiers,Job 类内部的加载关系发生了变化的主要内容,如果未能解决你的问题,请参考以下文章