由于 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 类内部的加载关系发生了变化的主要内容,如果未能解决你的问题,请参考以下文章

由于目标计算机积极拒绝,无法连接。

我在Android Studio工作,由于系统崩溃,一个或多个功能由于频繁的系统崩溃而崩溃。我应该如何恢复它?

SQL Server 服务由于登录失败而无法启动怎么办

Fiddler由于目标计算机积极拒绝,无法连接的解决方法

为啥我收到“由于保护级别而无法访问”错误?

SVN 由于目标机器积极拒绝,无法连接