You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 21:46:32