Laravel中如何恢复多层级关联的软删除模型?
Laravel恢复软删除模型时,关联的Invoice未被恢复
我正在开发一个Laravel应用,恢复包含多层关联的软删除模型时遇到问题:Contract和AcceptanceAct能成功恢复,但与AcceptanceAct关联的Invoice无法恢复,推测是多层级关联的加载问题。
当前恢复数据的代码:
$contract = Contract::withTrashed()->findOrFail($id); $contract->restore(); $contract->load(['acceptanceActs' => function ($query) { $query->withTrashed()->with('invoice'); }]); foreach ($contract->acceptanceActs as $act) { $act->restore(); if ($act->invoice) { $act->invoice->restore(); } } return response()->json();
模型定义如下:
Contract模型
/** * @return BelongsTo */ public function client(): BelongsTo { return $this->belongsTo(Client::class); } /** * @return HasMany */ public function acceptanceActs(): HasMany { return $this->hasMany(AcceptanceAct::class); }
AcceptanceAct模型
/** * @return BelongsTo */ public function client(): BelongsTo { return $this->belongsTo(Client::class); } /** * @return HasOne */ public function invoice(): HasOne { return $this->hasOne(Invoice::class); } /** * @return BelongsTo */ public function contract(): BelongsTo { return $this->belongsTo(Contract::class); }
Invoice模型
/** * @return BelongsTo */ public function client(): BelongsTo { return $this->belongsTo(Client::class); } /** * @return HasMany */ public function items(): HasMany { return $this->hasMany(InvoiceItem::class); } /** * @return BelongsTo */ public function acceptanceAct(): BelongsTo { return $this->belongsTo(AcceptanceAct::class); }
所有模型均已启用软删除(use SoftDeletes)。目前的问题是:Contract和AcceptanceAct恢复成功,但关联的Invoice始终未被恢复。
解决办法
1. 确保加载关联时包含软删除的Invoice
当前代码中,加载acceptanceActs时虽然用了withTrashed(),但关联的invoice默认不会加载软删除的记录,导致$act->invoice为null,自然无法执行恢复操作。修改加载关联的代码,给invoice也加上withTrashed():
$contract->load(['acceptanceActs' => function ($query) { $query->withTrashed()->with(['invoice' => function ($q) { $q->withTrashed(); }]); }]);
或者更简洁的写法:
$contract->load(['acceptanceActs' => fn($q) => $q->withTrashed()->with('invoice:withTrashed')]);
2. 验证关联关系及外键正确性
检查AcceptanceAct和Invoice的关联外键是否匹配:
AcceptanceAct的invoice()方法是hasOne(Invoice::class),默认会使用acceptance_act_id作为外键,确认invoices表中存在该字段且值正确关联到对应的acceptance_acts记录。- 确保
Invoice模型的acceptanceAct()关联外键也正确(如果自定义了外键,需要在关联方法中明确指定)。
3. 调试确认$act->invoice是否存在
在循环中加入调试代码,确认是否能获取到软删除的Invoice:
foreach ($contract->acceptanceActs as $act) { $act->restore(); // 调试输出,查看是否能拿到软删除的Invoice实例 dd($act->invoice); if ($act->invoice) { $act->invoice->restore(); } }
4. 批量恢复优化(可选)
如果关联数据量较大,可以用批量更新的方式提升效率,避免循环操作:
// 恢复Contract $contract->restore(); // 获取所有需要恢复的AcceptanceAct ID $actIds = $contract->acceptanceActs()->withTrashed()->pluck('id'); // 批量恢复AcceptanceAct AcceptanceAct::withTrashed()->whereIn('id', $actIds)->restore(); // 批量恢复关联的Invoice Invoice::withTrashed()->whereIn('acceptance_act_id', $actIds)->restore();
内容的提问来源于stack exchange,提问作者screw4445
相关产品推荐
相关产品推荐

