Laravel多对多关联:实现用户关联公司的更新或创建逻辑
问题
现有users表与companies表,通过company_user中间表实现多对多关联,可通过$user->companies()获取用户所有关联公司,$user->companies()->first()获取首个关联公司。需求是:若用户有关联公司则更新首个关联公司的信息,若无关联公司则创建新公司并与用户关联。
尝试的代码如下:
$company = $user->companies()->first()->updateOrCreate( [], ['name' => $validated['company_name']] ); $user->companies()->syncWithoutDetaching([ $company->id => ['relationship' => $user->type] ]);
这段代码在用户有关联公司时正常工作,但无关联公司时会触发No first() on null错误。
尝试直接调用关联的updateOrCreate:
$company = $user->companies()->updateOrCreate( ['relationship' => 'owner'], ['name' => $validated['company_name']] );
其中relationship是company_user中间表的字段,但这种写法不符合预期。
更新1:尝试以下代码后发现,会直接获取companies表的首个公司,忽略用户的关联状态(比如用户2无关联公司时,代码会修改用户1关联的公司1,而不是创建新公司):
$company = $user->companies()->updateOrCreate( [], ['name' => $validated['name']] );
解决方案
方法1:简洁条件判断(推荐)
直接判断用户是否存在首个关联公司,存在则更新,不存在则创建并关联:
$firstCompany = $user->companies()->first(); if ($firstCompany) { $firstCompany->update(['name' => $validated['company_name']]); $company = $firstCompany; } else { // 创建公司的同时,通过第二个参数传入中间表字段值完成关联 $company = $user->companies()->create( ['name' => $validated['company_name']], ['relationship' => $user->type] ); }
方法2:关联范围限定的updateOrCreate写法
如果想用updateOrCreate实现,需要先通过关联限定查询范围,再处理中间表关联:
// 限定查询当前用户的关联公司,尝试更新首个记录 $company = $user->companies()->limit(1)->updateOrCreate( [], ['name' => $validated['company_name']] ); // 若为新创建的公司,补充中间表关联字段 if (!$user->companies()->where('id', $company->id)->exists()) { $user->companies()->attach($company->id, ['relationship' => $user->type]); }
注:这种写法逻辑不如第一种直观,推荐优先使用方法1。
关键说明
- 多对多关联的
updateOrCreate默认基于companies表字段查询,不会自动关联中间表条件,因此直接调用$user->companies()->updateOrCreate()时,空查询条件会匹配整个companies表的第一条数据,而非当前用户的关联数据。 - 多对多关联的
create()方法支持第二个参数传入中间表属性,可一步完成公司创建与关联,无需额外调用syncWithoutDetaching或attach。
内容的提问来源于stack exchange,提问作者carbonisle
相关产品推荐
相关产品推荐

