Laravel队列Mailable中预加载关联数据在build方法丢失问题
Laravel队列发送Mailable时Eloquent预加载关联丢失问题成因
根本原因
问题出在Mailable类引入的SerializesModels trait的序列化机制,和预加载逻辑、参数传递流程无关:
- 所有使用
SerializesModelstrait的队列任务(含队列发送的邮件、通知、普通Job),序列化Eloquent模型/集合时不会把内存中已经加载的关联数据、模型附加属性完整写入队列payload,只会记录每个模型的类名、主键ID、数据库连接信息。 - 队列Worker消费任务反序列化时,会根据记录的主键ID重新从数据库查询对应模型实例,这个重新查询的过程不会自动携带你之前在请求生命周期里提前预加载的关联关系,因此反序列化后拿到的模型
relations属性为空数组,预加载数据全部丢失。
现象匹配说明
- 你在Repository返回处、控制器方法内、Mailable构造函数中打印数据能看到完整关联,是因为这些逻辑全部运行在队列任务序列化之前的HTTP请求生命周期,此时操作的是内存中原始的带预加载关联的集合对象,还没触发序列化替换逻辑。
- 等到Mailable的
build方法执行时,已经是队列Worker拉取任务、完成反序列化的阶段,此时的$this->domaines是重新查库得到的裸模型集合,自然没有之前预加载的关联。 - 你在
build方法中手动调用Repository查询能拿到完整关联,是因为这次查询发生在Worker执行阶段,完整走了一遍带with('actualite')的预加载逻辑,和序列化流程无关。
修复方案
- 方案1:移除Mailable类中的
SerializesModelstrait引入。此时框架会把整个集合(含已加载关联)完整序列化存入队列payload,反序列化时不会重新查库,关联数据会完整保留。注意如果单批集合数据量较大,会适当增加队列存储的占用,数据量不大的场景下这个方案实现成本最低。 - 方案2:保留
SerializesModelstrait,在build方法中对反序列化得到的$this->domaines手动调用load('actualite')做延迟关联加载,不需要重复写全量查询逻辑,性能开销更小。 - 方案3:就是你已经验证可行的写法,直接在
build方法中调用Repository方法重新查询带预加载的完整集合,适合查询逻辑包含复杂过滤、不想把大体积集合存入队列payload的场景。
内容的提问来源于stack exchange,提问作者user16761658
相关产品推荐
相关产品推荐

