如何在Diesel中批量Upsert(插入更新)数组数据?
批量执行PostgreSQL Upsert的正确方式(Diesel框架)
问题场景
尝试用Diesel的AsChangeSet实现批量Upsert(处理从外部源获取的数组数据),数据库为PostgreSQL(无法使用元组语法),原代码如下:
let new_users = vec![user1, user2]; diesel::insert_into(users) .values(&new_users) .on_conflict(id) .do_update() .set(&new_users) .execute(&conn);
编译报错:&Vec<User>未实现AsChangeSet trait(尽管单个User已实现该trait)。
解决方案
方式一:用excluded引用插入字段(推荐)
PostgreSQL的Upsert逻辑支持引用待插入行的字段值来更新冲突行,Diesel通过excluded函数提供该能力,无需依赖AsChangeSet:
use diesel::dsl::excluded; let new_users = vec![user1, user2]; diesel::insert_into(users) .values(&new_users) .on_conflict(id) .do_update() .set(( name.eq(excluded(name)), email.eq(excluded(email)), // 按需添加其他需要更新的字段 )) .execute(&conn)?;
方式二:将数组转为单个变更集的迭代器
如果User已实现AsChangeSet,可以将数组中每个元素转为变更集,再传递给set:
let new_users = vec![user1, user2]; diesel::insert_into(users) .values(&new_users) .on_conflict(id) .do_update() .set(new_users.iter().map(|user| user.as_change_set())) .execute(&conn)?;
此方式适合字段较多的场景,代码更简洁,但要求AsChangeSet实现覆盖所有需要更新的字段。
报错原因
AsChangeSet trait仅为单个User实体实现,而原代码中set(&new_users)尝试将整个数组作为变更集,数组类型未默认实现该trait,因此编译失败。
内容的提问来源于stack exchange,提问作者user1350184
相关产品推荐
相关产品推荐

