TypeORM 是否包含一些功能来避免这种情况:
let contraption = await thingRepository.findOne({ name : "Contraption" });
if(!contraption) // Create if not exist
{
let newThing = new Thing();
newThing.name = "Contraption"
await thingRepository.save(newThing);
contraption = newThing;
}
类似:
let contraption = await thingRepository.upsert({ name : "Contraption" });
正如 Tomer Amir 所指出的,目前有一个针对 real upsert 的部分解决方案,并且功能请求是在 TypeORM 的存储库上打开的 ATM :
部分解决方案:
await connection.createQueryBuilder()
.insert()
.into(Post)
.values(post2)
.onConflict(`("id") DO NOTHING`)
.execute();
await connection.createQueryBuilder()
.insert()
.into(Post)
.values(post2)
.onConflict(`("id") DO UPDATE SET "title" = :title`)
.setParameter("title", post2.title)
.execute();
旧答案实际上指向执行OP要求的“更新”方式:
已经有一个方法了:
Repository<T>.save()
,其中文档说:
将所有给定实体保存在数据库中。如果实体不存在于 然后数据库插入,否则更新。
但是,如果您不指定 id 或唯一的字段集,则 save 方法无法知道您正在引用现有数据库对象。
所以使用 typeORM 更新插入是:
let contraption = await thingRepository.save({id: 1, name : "New Contraption Name !"});
对于 2021 年发现此问题的任何人,如果 Typeorm 的
Repository.save()
方法找到与主键匹配的内容,它将更新或插入。这也适用于 sqlite。
来自文档:
/**
* Saves all given entities in the database.
* If entities do not exist in the database then inserts, otherwise updates.
*/
现在你可以使用
upsert
方法,
await this.yourRepository.upsert({name: 'John'}, ['id']) // assuming id is unique
首先使用
Unique
装饰器定义该约束
@Entity()
@Unique('constraint_name', ['col_one', 'col_two'])
然后在代码中就可以使用
upsert
方法了。
await this.yourRepository.upsert({name: 'John'}, ['constraint_name'])
使用 INSERT IGNORE 忽略 MySQL 和 Postgres 上的重复项:
await connection.createQueryBuilder()
.insert()
.into(Post)
.values(post)
.orIgnore()
.execute();
当
ONCONFLICT
不适用于 MySQL 时,这可能会有所帮助。来自Github
await getConnection()
.createQueryBuilder()
.insert()
.into(GroupEntity)
.values(updatedGroups)
.orUpdate({ conflict_target: ['id'], overwrite: ['name', 'parentId', 'web', 'avatar', 'description'] })
.execute();
对于任何正在寻找更新插入多条记录的方法并使用 Postgres 和 TypeORM 的人,您可以通过排除的关键字访问您尝试更新/插入的行。
const posts = [{ id: 1, title: "First Post" }, { id: 2, title: "Second Post" }];
await connection.createQueryBuilder()
.insert()
.into(Post)
.values(posts)
.onConflict(`("id") DO UPDATE SET "title" = excluded."title"`)
.execute();
这对我有用。
我结合了@DedaDev的答案。
您的实体
@Entity()
@Unique('constraint_name', ['id'])
您的服务
await this.yourRepository.upsert(
{
id: uuid,
key1: value1,
...
},
{
skipUpdateIfNoValuesChanged: true, // If true, postgres will skip the update if no values would be changed (reduces writes)
conflictPaths: ['id'], // column(s) name that you would like to ON CONFLICT
},
);
2021 答案:v0.2.40 添加了对 TypeORM 的原生 upsert 支持
现在有一个库可以插入 TypeORM 来帮助做到这一点。
您可能想从 Repository 类中查看“预加载”方法:https://typeorm.delightful.studio/classes/repository_repository.repository.html#preload
从给定的计划 javascript 对象创建一个新实体。如果实体已存在于数据库中,则会加载该实体(以及与其相关的所有内容),将所有值替换为给定对象中的新值,然后返回该新实体。这个新实体实际上是从数据库实体加载的,所有属性都从新对象替换。请注意,给定的类实体对象必须具有实体 id/主键来查找实体。如果未找到具有给定 ID 的实体,则返回未定义。
如上所述,限制是需要通过ID来搜索。
在 2024 年,使用 NestJS 和 TypeORM,您可以使用 upsert 并处理所有边缘情况。
假设您有一个具有名称和颜色的实体 Thing
@Entity("thing")
@Unique(["name", "color"])
export class Thing {
@PrimaryGeneratedColumn()
id: string;
@Column()
name: string;
@Column()
color: string;
// list goes on
}
事情的
id
在整个数据库的其他表中使用,导致臭名昭著
错误:表“事物”上的更新或删除违反了外键约束...
您仍然可以使用
upsert
以及详细选项
await repository.upsert(
[
{ name: "a red thing", color: "red" },
{ name: "a blue thing", color: "blue" },
],
{
conflictPaths: ["name", "color"],
skipUpdateIfNoValuesChanged: true,
upsertType: "on-conflict-do-update",
}
);
如果还是不行,那你就有防弹了
const repository = dataSource.getRepository(Thing);
await repository
.createQueryBuilder()
.insert()
.into(Thing)
.values([
{ name: "a red thing", color: "red" },
{ name: "a blue thing", color: "blue" },
])
.orUpdate(["name", "color"])
.orIgnore()
.execute();
在此处以用户身份记录您的实体
@OneToMany(type => Post, post => post.user, {
cascade: true
})
posts: Post[];
export const saveAllPosts = async (req: Request, res: Response) => {
const userRepository = getManager().getRepository(User);
const postRepository = getManager().getRepository(Post);
let i;
let newUsers:any = [];
let newUser:any = {};
let newPost:any = {};
for(i=1; i<=6; i ++) {
newUser = await userRepository.findOne({
where: { id: i}
});
if(typeof newUser == "undefined") {
newUser = new User();
console.log("insert");
} else {
console.log("update");
}
newUser.name = "naval pankaj test"+i;
newPost = await postRepository.findOne({
where: { userId: i}
});
if(typeof newPost == "undefined") {
newPost = new Post();
console.log("post insert");
} else {
console.log("post update");
}
newPost.title = "naval pankaj add post title "+i;
newUser.posts = [newPost];
newUsers.push(newUser);
}
await userRepository.save(newUsers);
res.send("complete");
};