Laravel中firstOrNew结合关联查询实现数据增改的问题
搞定user_sales表的同款「存在更新/不存在创建」逻辑
嘿,我完全get你的需求!既然user_buys用firstOrNew实现了「同用户、同item、同日期的条目存在就更新value,不存在就新建」的逻辑,把这套逻辑搬到user_sales表其实非常简单,甚至还能优化得更通用,给你分几种情况说:
直接复用逻辑(最快上手)
因为两张表结构类似,你只需要把模型类从UserBuy换成对应的UserSale就行,代码几乎一模一样:
// 处理user_sales表的条目 $entry = UserSale::firstOrNew([ 'item_id' => $item_id, 'user_id' => Auth::id(), 'date' => $date ]); $entry->value = $value; $entry->save();
只要你的UserSale模型正确关联到user_sales表(Laravel默认会按类名复数映射,没特殊情况不用额外配置),这段代码就能完美复刻user_buys的逻辑。
进阶封装:避免重复代码
如果以后还有更多类似结构的表,总复制粘贴代码太麻烦,不如封装一个通用方法,放在工具类或者你的基础模型里:
// 通用的「存在更新/不存在创建」方法 function upsertEntry(string $modelClass, array $uniqueConditions, array $updateData) { $entry = $modelClass::firstOrNew($uniqueConditions); // 批量赋值要更新的字段 foreach ($updateData as $key => $value) { $entry->$key = $value; } $entry->save(); return $entry; } // 用的时候就很清爽: // 处理user_buys upsertEntry(UserBuy::class, [ 'item_id' => $item_id, 'user_id' => Auth::id(), 'date' => $date ], ['value' => $value]); // 处理user_sales upsertEntry(UserSale::class, [ 'item_id' => $item_id, 'user_id' => Auth::id(), 'date' => $date ], ['value' => $value]);
更高效的方案:用Laravel的upsert方法(Laravel 8+可用)
如果你用的是Laravel 8及以上版本,推荐用upsert方法,它直接利用数据库的INSERT ... ON DUPLICATE KEY UPDATE逻辑,只需要一次SQL操作,比firstOrNew先查后改更高效:
// user_sales的upsert写法 UserSale::upsert( // 要插入/更新的数据 [ [ 'item_id' => $item_id, 'user_id' => Auth::id(), 'date' => $date, 'value' => $value ] ], // 用来判断条目标识的唯一字段组合 ['item_id', 'user_id', 'date'], // 当条目存在时需要更新的字段 ['value'] );
⚠️ 注意:用upsert的话,必须给你的user_sales表在item_id、user_id、date这三个字段上创建联合唯一索引,否则数据库会允许重复插入,触发报错。
内容的提问来源于stack exchange,提问作者sveti petar
相关产品推荐
相关产品推荐

