Laravel关联表数组批量更新报错,求正确实现代码
Laravel 主表与关联子表批量更新解决方案
问题根源
hasMany关联的update()方法仅支持统一更新所有关联记录为相同值,无法直接批量更新每条子表记录的不同字段值。Invoice_detail模型未将sort_order加入$fillable,导致批量赋值时被过滤,触发字段为空报错。- 未处理子表记录的新增、修改、删除逻辑,仅单纯覆盖数据会导致数据不一致。
- 路由定义中
/invoic拼写错误,与实际资源路由规范不符,可能导致请求参数无法正确接收。
修正后的代码实现
1. 调整Invoice_detail模型
添加sort_order到批量赋值白名单:
class Invoice_detail extends Model { use HasFactory; protected $table = 'invoice_details'; protected $primaryKey = 'id'; // 新增sort_order字段到fillable protected $fillable = ['title', 'quantity', 'unit_price', 'invoice_id', 'sort_order']; const UPDATED_AT = 'modified'; const CREATED_AT = 'created'; public function invoice(){ return $this->belongsTo(Invoice::class); } }
2. 重写Update控制器方法
实现子表的新增、修改、删除完整逻辑:
public function update(Request $request, string $id) { // 验证请求数据(可选但推荐,避免非法数据) $request->validate([ 'user' => 'required', 'company' => 'required', 'invoice_month' => 'required', 'title.*' => 'required', 'quantity.*' => 'required|integer', 'unit_price.*' => 'required|numeric', 'sort_order.*' => 'required|integer', 'detail_id.*' => 'nullable|exists:invoice_details,id' ]); // 更新主表数据 $invoice = Invoice::findOrFail($id); $invoice->update($request->only(['user', 'company', 'invoice_month'])); // 处理子表数据 $existingDetailIds = []; $detailIds = $request->input('detail_id', []); $titles = $request->title; $quantities = $request->quantity; $unitPrices = $request->unit_price; $sortOrders = $request->sort_order; foreach ($titles as $index => $title) { $detailData = [ 'title' => $title, 'quantity' => $quantities[$index], 'unit_price' => $unitPrices[$index], 'sort_order' => $sortOrders[$index], 'invoice_id' => $invoice->id ]; if (!empty($detailIds[$index])) { // 更新已有子表记录 Invoice_detail::where('id', $detailIds[$index])->update($detailData); $existingDetailIds[] = $detailIds[$index]; } else { // 新增子表记录 $newDetail = $invoice->invoice_detail()->create($detailData); $existingDetailIds[] = $newDetail->id; } } // 删除前端移除的子表记录 if (!empty($existingDetailIds)) { $invoice->invoice_detail()->whereNotIn('id', $existingDetailIds)->delete(); } else { // 若没有提交任何子表记录,清空所有关联数据 $invoice->invoice_detail()->delete(); } return redirect('invoice')->with('flash_message', '更新成功'); }
3. 修正路由拼写错误
将错误的/invoic改为规范的/invoice:
Route::get('invoice', [InvoiceController::class, 'index']); Route::get('search', [InvoiceController::class, 'search']); // 修正路由拼写错误 Route::resource('/invoice', InvoiceController::class);
4. 视图提交数据规范
Bootstrap表格提交数组时,需确保表单元素name属性为数组格式,同时传递子表ID区分新增/更新:
<!-- 表格行示例 --> <tr> <td> <!-- 隐藏域存储子表ID,新增行留空 --> <input type="hidden" name="detail_id[]" value="{{ $detail->id ?? '' }}"> <input type="text" name="title[]" value="{{ $detail->title ?? '' }}" class="form-control"> </td> <td> <input type="number" name="quantity[]" value="{{ $detail->quantity ?? 1 }}" class="form-control"> </td> <td> <input type="number" step="0.01" name="unit_price[]" value="{{ $detail->unit_price ?? 0 }}" class="form-control"> </td> <td> <input type="number" name="sort_order[]" value="{{ $detail->sort_order ?? ($loop->index + 1) }}" class="form-control"> </td> </tr>
内容的提问来源于stack exchange,提问作者babe_engineer
相关产品推荐
相关产品推荐

