Laravel+Vue表单提交时如何将主键作为外键存入另一表?
问题描述
我有两张关联的数据表,希望通过单个表单提交数据时,自动将parties表新增记录的主键作为外键存入corraddresses的party_id字段,但目前提交时要么只有parties表存入数据,要么触发非空约束错误。以下是我的代码:
数据表迁移
parties表
public function up() { Schema::create('parties', function (Blueprint $table) { $table->id(); $table->string('full_name'); $table->string('ic_passport'); $table->string('nationality'); $table->string('income_tax_no'); $table->string('income_Tax_filing_branch'); $table->string('phone_no'); $table->string('email'); $table->timestamps(); }); }
corraddresses表
public function up() { Schema::create('corraddresses', function (Blueprint $table) { $table->id(); $table->unsignedBigInteger('party_id'); $table->foreign('party_id')->references('id')->on('parties'); $table->string('address_1'); $table->string('address_2'); $table->string('city'); $table->string('poscode'); $table->timestamps(); }); }
模型代码
Party模型
class Party extends Model { use HasFactory; protected $fillable = ['full_name','ic_passport','nationality','income_tax_no', 'income_Tax_filing_branch','phone_no','email']; }
Corraddress模型
class Corraddress extends Model { use HasFactory; protected $fillable = ['address_1','address_2','city','poscode','party_id']; public function partyId() { return $this->belongsTo(Party::class, 'party_id', 'id'); } }
控制器代码
PartyController的store方法
public function store(Request $request) { $party = Party::create($request->post()); return response()->json([ 'message'=>'Party Created Successfully!!', 'party'=>$party ]); }
CorraddressController的store方法
public function store(Request $request) { $corraddress = Corraddress::create($request->post()); return response()->json([ 'message'=>'Corraddress Created Successfully!!', 'corraddress'=>$corraddress ]); }
前端表单脚本
data() { return { full_name: '', ic_passport: '', nationality: '', income_tax_no: '', income_Tax_filing_branch: '', phone_no: '', email: '', address_1: '', address_2: '', city: '', poscode: '', party_id: '', }; }, methods: { addNewPost(){ axios.post('/api/auth/party',{ full_name: this.full_name, ic_passport: this.ic_passport, nationality: this.nationality, income_tax_no: this.income_tax_no, income_Tax_filing_branch: this.income_Tax_filing_branch, phone_no: this.phone_no, email: this.email, }) axios.post('/api/auth/corraddress',{ address_1: this.address_1, address_2: this.address_2, city: this.city, poscode: this.poscode, party_id: response.party.id, // party_id: this.party_id, }) }, },
当前问题
- 保留
party_id: response.party.id时,只有parties表存入数据,corraddresses无数据 - 取消注释
party_id: this.party_id时,触发SQL错误:
message "SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'party_id' cannot be null (SQL: insert into `corraddresses` (`address_1`, `address_2`, `city`, `poscode`, `party_id`, `updated_at`, `created_at`) values (awgawg, awgawg, gawg, awgaw, ?, 2022-11-08 04:31:58, 2022-11-08 04:31:58))"
解决方案
问题核心在前端异步请求的顺序处理和变量作用域,同时可以优化模型关联规范:
1. 前端修复:处理异步请求依赖
axios请求是异步的,当前写法会同时发送两个请求,第二个请求无法获取第一个请求的返回结果,且response变量未定义。需要用async/await或then链式调用确保先创建Party,再用返回ID创建地址:
修改后的前端方法:
async addNewPost(){ try { // 等待Party创建完成,获取返回数据 const partyRes = await axios.post('/api/auth/party',{ full_name: this.full_name, ic_passport: this.ic_passport, nationality: this.nationality, income_tax_no: this.income_tax_no, income_Tax_filing_branch: this.income_Tax_filing_branch, phone_no: this.phone_no, email: this.email, }); // 使用返回的party ID创建地址 await axios.post('/api/auth/corraddress',{ address_1: this.address_1, address_2: this.address_2, city: this.city, poscode: this.poscode, party_id: partyRes.data.party.id, }); alert('数据提交成功'); // 重置表单 Object.assign(this.$data, this.$options.data.call(this)); } catch (err) { console.error('提交失败:', err); alert('提交出错,请重试'); } }
2. 模型关联优化(规范写法)
Corraddress模型的关联方法名建议改为party(符合Laravel命名规范),同时在Party模型添加反向关联:
// Corraddress模型修改关联方法 public function party() { return $this->belongsTo(Party::class, 'party_id', 'id'); } // Party模型添加反向关联 public function corraddresses() { return $this->hasMany(Corraddress::class, 'party_id'); }
3. 可选:后端合并接口(简化逻辑)
可以在后端写统一接口,一次性处理两个表的创建,避免前端处理异步顺序,同时用事务保证数据一致性:
在PartyController新增方法:
use Illuminate\Support\Facades\DB; public function storeWithAddress(Request $request) { // 验证请求数据 $validated = $request->validate([ 'full_name' => 'required|string', 'ic_passport' => 'required|string', 'nationality' => 'required|string', 'income_tax_no' => 'required|string', 'income_Tax_filing_branch' => 'required|string', 'phone_no' => 'required|string', 'email' => 'required|email', 'address_1' => 'required|string', 'address_2' => 'nullable|string', 'city' => 'required|string', 'poscode' => 'required|string', ]); // 事务确保数据要么都创建成功,要么都回滚 DB::transaction(function () use ($validated) { $party = Party::create([ 'full_name' => $validated['full_name'], 'ic_passport' => $validated['ic_passport'], 'nationality' => $validated['nationality'], 'income_tax_no' => $validated['income_tax_no'], 'income_Tax_filing_branch' => $validated['income_Tax_filing_branch'], 'phone_no' => $validated['phone_no'], 'email' => $validated['email'], ]); // 通过关联创建地址,自动填充party_id $party->corraddresses()->create([ 'address_1' => $validated['address_1'], 'address_2' => $validated['address_2'], 'city' => $validated['city'], 'poscode' => $validated['poscode'], ]); }); return response()->json(['message' => 'Party及地址创建成功']); }
前端只需发送一次请求:
async addNewPost(){ try { await axios.post('/api/auth/party-with-address',{ full_name: this.full_name, ic_passport: this.ic_passport, nationality: this.nationality, income_tax_no: this.income_tax_no, income_Tax_filing_branch: this.income_Tax_filing_branch, phone_no: this.phone_no, email: this.email, address_1: this.address_1, address_2: this.address_2, city: this.city, poscode: this.poscode, }); alert('提交成功'); this.$data = this.$options.data.call(this); } catch (err) { console.error(err); alert('提交失败'); } }
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

