Laravel使用hydrate填充模型仅主键有值其余字段为空如何解决
问题原因
你没有错误使用hydrate()方法,问题出在SQL查询逻辑:
- 你使用
SELECT *对两张表做左关联查询,除了关联键operation_id(使用USING关键字查询结果只会保留一个)外,两张表的同名字段会被后查询的operations表字段覆盖。 - 由于你筛选的是
o.operation_id IS NULL的记录,operations表的所有字段返回值都是null,因此最终拿到的查询结果里除了operation_id,其余字段都是空值,才会出现插入后只有主键有值的情况。
修复方案
快速修复
只需将SQL语句中的SELECT *修改为SELECT u.*,明确只取upload_operations表的字段即可解决空值问题:
$new_uploads = DB::select(' SELECT u.* FROM upload_operations u LEFT JOIN operations o USING (operation_id) WHERE o.operation_id IS NULL');
更优实现方案
你当前的逐行插入方案性能较差,数据量大时容易超时,推荐用查询构造器+批量插入的方式实现,逻辑更简洁性能更高:
public function handle() { // 直接查询出所有待新增的上传记录 $toInsert = UploadOperation::whereNotIn('operation_id', Operation::pluck('operation_id')) ->get() ->map(fn ($record) => $record->only([ 'certifier_name', 'certifier_website', 'certifier_email_address', 'operation_id', 'operation_name', // 其余需要同步的字段 ])) ->toArray(); Log::info('New operations count: ' . count($toInsert)); // 批量插入,避免循环逐行写入 if (!empty($toInsert)) { Operation::insert($toInsert); } return Action::message('New uploads added!'); }
增量同步通用方案
如果需要同时处理新增和更新的同步需求,不需要自己做表关联比对,可以直接使用Laravel内置的upsert方法一步完成:
public function handle() { $allUploads = UploadOperation::all()->toArray(); Log::info('Upload operations count: ' . count($allUploads)); // 第一个参数为待写入数据,第二个参数为冲突判断主键,第三个参数为冲突时需要更新的字段 Operation::upsert( $allUploads, ['operation_id'], ['certifier_name', 'certifier_website', 'certifier_email_address', 'operation_name'] ); return Action::message('Uploads synced successfully!'); }
内容的提问来源于stack exchange,提问作者jrmypttrsn
相关产品推荐
相关产品推荐

