Laravel多选下拉框更新时触发SQLSTATE[HY000]:1366整数值错误求助
嘿,我看你遇到的问题很典型——从单选改成多选后,数据库字段类型不匹配导致的错误。咱们一步步来解决:
错误原因分析
你看到的SQLSTATE[HY000]: General error: 1366 Incorrect integer value: '["1"]' for column 'operation_id'错误,是因为你的offers表中operation_id字段是单个整数类型,但现在你提交的是一个数组(比如["1"]),直接把数组赋值给单个整数字段就会报错。
而且你已经用了多对多关联($offer->operations()->attach()和sync()),这说明你应该用中间表来存储关联关系,而不是把operation_id存在offers表本身。
步骤1:移除offers表中不必要的operation_id字段(可选但推荐)
既然用了多对多关联,offers表的operation_id字段是单选时代码遗留的,现在可以删掉它(记得先备份数据)。如果暂时不想删,至少不要再往这个字段里写值。
步骤2:修改控制器的Store和Update方法
在store和update方法里,你现在还把operation_id包含在$request->only()里,这会尝试把数组写入offers表的operation_id字段,这就是错误的根源。
修改Store方法:
public function store(OfferRequest $request) { // 移除only里的'operation_id' $offer = Offer::create($request->only('price', 'hotel_included', 'recommended_stay', 'hospitalisation', 'visible', 'doctor_id', 'hotel_id', 'price_fixed', 'currency', 'promote', 'first_picture')); $offer->translations()->create([ 'language_code' => env('APP_LOCAL', app()->getLocale()), 'title' => $request->title, 'features' => $request->features, ]); // 直接用request的operation_id数组,不用取keys(提交的operation_id[]本身就是id数组) $offer->operations()->attach($request->input('operation_id')); return redirect()->route('admin.offers.index')->with('success', 'Une nouvelle offre a été enregistrée'); }
修改Update方法:
public function update(OfferRequest $request, Offer $offer) { // 同样移除only里的'operation_id' $offer->update($request->only('price', 'hotel_included', 'recommended_stay', 'hospitalisation', 'visible', 'doctor_id', 'hotel_id', 'price_fixed', 'currency', 'promote', 'first_picture')); $language = \App\Models\Language::where('language', request()->input('lang', env('APP_LANG', 'fr_FR')))->firstOrFail(); $offer->translations()->updateOrCreate( ['offer_id' => $offer->id, 'language_code' => $language->language], $request->only('title', 'features') ); // 直接用request的operation_id数组同步关联 $offer->operations()->sync($request->input('operation_id')); return redirect()->route('admin.offers.index')->with('success', "L'offre a été mise à jour"); }
步骤3:修复视图中的选中逻辑
你原来的视图里选中判断逻辑混乱,合并优化成下面的写法:
<label for="operation_id" class="text-gray-700 inline-block">Opération</label> <select class="focus:outline-none outline-none w-full px-3 py-2 border rounded {{ $errors->has('operation_id') ? 'border-red-400' : '' }} select-checkbox" name="operation_id[]" id="operation_id" multiple> @php // 统一处理旧输入和编辑页面的已选数据 $selectedIds = old('operation_id', isset($offer) ? $offer->operations->pluck('id')->toArray() : []); @endphp @foreach ($operations as $operation) <option value="{{ $operation->id }}" {{ in_array($operation->id, $selectedIds) ? 'selected' : '' }}>{{ $operation->translation->name }}</option> @endforeach </select> @if ($errors->has('operation_id')) <div class="invalid-feedback"> <strong>{{ $errors->first('operation_id') }}</strong> </div> @endif
这样无论是创建页面(无$offer)还是编辑页面,都能正确显示选中的选项,同时处理表单验证后的旧输入。
步骤4:更新表单验证规则
在OfferRequest里,把operation_id的验证规则改成数组类型:
public function rules() { return [ // ...其他规则 'operation_id' => 'required|array', 'operation_id.*' => 'exists:operations,id', // 确保每个选中的id都在operations表中存在 // ...其他规则 ]; }
最后检查模型关联
确保你的Offer模型和Operation模型已经正确定义了多对多关联:
Offer模型:
public function operations() { return $this->belongsToMany(Operation::class); }
Operation模型:
public function offers() { return $this->belongsToMany(Offer::class); }
并且你已经创建了中间表(默认是offer_operation,包含offer_id和operation_id两个整数字段)。
做完这些修改后,你的多选下拉框应该就能正常工作了!
内容的提问来源于stack exchange,提问作者Jeremy

