Laravel 10关联数据插入:已知源名称获取外键ID的实现方案
问题:Laravel 10中通过源名称获取ID批量插入数据
我需要在Laravel 10中插入数据,外键source_id为int类型(示例值:2),但Python爬虫程序只能传入源名称(示例值:facebook.com),无法每次调用API获取源ID。源表数据场景如下:
- 1: google.com
- 2: facebook.com
现有模型代码(PropertyVault模型)
public function propertySource(): HasMany { return $this->hasMany(PropertySource::class); } public function propertyNetworkPost(): HasMany{ return $this->hasMany(PropertyNetworkPost::class); }
现有控制器代码
public function storeUrl(Request $request){ if(!$request->ad_urls){ return response()->json([ 'status'=>'failed', 'notification'=>__('Tidak ada input') ]); } ///解码嵌套JSON $ad_urls = $request->ad_urls ?? []; if(!is_array($ad_urls)){ $ad_urls = json_decode($request->ad_urls,true); } ///创建批量插入数组 $input = []; foreach($ad_urls as $item){ $input [] = [ 'country' => $request->country, 'source_id' => $request->source, // 此处为问题点:已知名称需获取对应ID 'ad_url' => $item, ]; } try{ ///存在重复则忽略,并获取受影响行数 $rows = PropertyVault::insertOrIgnore($input); if(empty($rows)){ throw new PropertyException(message: 'no url to insert'); } } catch(Exception $e){ throw new PropertyException(message: $e->getMessage()); } return response()->json([ 'status' => 'success', 'message' => __("Inserting {$rows} urls"), ]); }
尝试过的代码(存在问题:插入到父模型)
$propertySource = PropertySource::where('name',$request->source)->first(); $status = $propertySource->propertyVault()->create([ 'country' => 'ID', 'source_id' => 1, 'ad_url' => 'https://google'.rand(0,1999).'.com', ]);
解决方案
1. 修正关联关系
首先在PropertySource模型中添加与PropertyVault的关联(确保外键指向正确):
use Illuminate\Database\Eloquent\Relations\HasMany; class PropertySource extends Model { // ... 其他模型代码 public function propertyVaults(): HasMany { return $this->hasMany(PropertyVault::class, 'source_id'); } }
2. 修改控制器逻辑
先根据传入的源名称查询对应的ID,再批量插入数据,同时增加源名称存在性校验:
public function storeUrl(Request $request) { if (!$request->ad_urls) { return response()->json([ 'status' => 'failed', 'notification' => __('Tidak ada input') ]); } // 校验源名称是否存在,避免插入无效外键 $propertySource = PropertySource::where('name', $request->source)->first(); if (!$propertySource) { return response()->json([ 'status' => 'failed', 'notification' => __('源名称不存在') ]); } $sourceId = $propertySource->id; // 解码嵌套JSON $ad_urls = $request->ad_urls ?? []; if (!is_array($ad_urls)) { $ad_urls = json_decode($request->ad_urls, true); } // 构建批量插入数组 $input = []; foreach ($ad_urls as $item) { $input[] = [ 'country' => $request->country, 'source_id' => $sourceId, // 使用查询到的合法ID 'ad_url' => $item, ]; } try { // 存在重复则忽略,获取受影响行数 $rows = PropertyVault::insertOrIgnore($input); if (empty($rows)) { throw new PropertyException(message: 'no url to insert'); } } catch (Exception $e) { throw new PropertyException(message: $e->getMessage()); } return response()->json([ 'status' => 'success', 'message' => __("Inserting {$rows} urls"), ]); }
3. 可选优化:缓存源映射
如果源数据不频繁更新,可以缓存名称与ID的映射,减少数据库查询次数:
// 从缓存获取,不存在则查询数据库并缓存 $sourceId = Cache::remember("source_id_{$request->source}", 3600, function () use ($request) { $source = PropertySource::where('name', $request->source)->value('id'); if (!$source) { abort(400, '源名称不存在'); } return $source; });
内容的提问来源于stack exchange,提问作者Raden Bagus
相关产品推荐
相关产品推荐

