我正在尝试更新 Prisma 中的一对多关系。我的架构看起来像这样
model A_User {
id Int @id
username String
age Int
bio String @db.VarChar(1000)
createdOn DateTime @default(now())
features A_Features[]
}
model A_Features {
id Int @id @default(autoincrement())
description String
A_User A_User? @relation(fields: [a_UserId], references: [id])
a_UserId Int?
}
我正在尝试向 id 为 1 的用户添加一些新功能,或者如果它们已经存在则更新它们。
我正在尝试做类似的事情
const post = await prisma.a_User.update({
where: { id: 1},
data: {
features: {
upsert: [
{ description: 'first feature'},
{ description: 'second feature'}
]
}
}
})
编译器不高兴,它告诉我
Type '{ features: { upsert: { description: string; }[]; }; }' is not assignable to type '(Without<A_UserUpdateInput, A_UserUncheckedUpdateInput> & A_UserUncheckedUpdateInput) | (Without<...> & A_UserUpdateInput)'.
Object literal may only specify known properties, and 'features' does not exist in type '(Without<A_UserUpdateInput, A_UserUncheckedUpdateInput> & A_UserUncheckedUpdateInput) | (Without<...> & A_UserUpdateInput)'.ts(2322)
index.d.ts(1572, 5): The expected type comes from property 'data' which is declared here on type '{ select?: A_UserSelect; include?: A_UserInclude; data: (Without<A_UserUpdateInput, A_UserUncheckedUpdateInput> & A_UserUncheckedUpdateInput) | (Without<...> & A_UserUpdateInput); where: A_UserWhereUniqueInput; }'
(property) features: {
upsert: {
description: string;
}[];
}
我不知道该怎么做,也无法在文档中找到明确的帮助。关于如何实现它或在哪里可以找到一些示例的任何想法?
答案 0 :(得分:1)
我正在根据您在评论中提供的说明提供我的解决方案。首先,我将对您的架构进行以下更改。
model A_User {
id Int @id
username String
age Int
bio String @db.VarChar(1000)
createdOn DateTime @default(now())
features A_Features[]
}
model A_Features {
id Int @id @default(autoincrement())
description String @unique
users A_User[]
}
值得注意的是,A_User
和 A_Features
之间的关系现在是多对多的。因此,单个 A_Features
记录可以连接到多个 A_User
记录(以及相反的情况)。
此外,A_Features.description
现在是唯一的,因此可以仅使用它的描述来唯一地搜索某个特征。
您可以阅读 Prisma Guide on Relations 以了解有关多对多关系的更多信息。
同样,根据您在评论中提供的说明,更新操作将执行以下操作:
覆盖 features
记录中的现有 A_User
。因此,任何先前的 features
都将断开连接并替换为新提供的。请注意,之前的 features
不会从 A_Features
表中删除,但它们只会从 A_User.features
关系中断开。
创建 A_Features
表中尚不存在的新提供的功能,并连接 A_Features
表中已存在的提供的功能{1}} 个表。
您可以使用两个单独的 update
查询来执行此操作。第一次更新将断开所有先前连接的 features
为所提供的 A_User
。第二个查询将连接或创建 features
表中新提供的 A_Features
。最后,您可以使用 transactions API 来确保两个操作按顺序并一起发生。事务 API 将确保如果两个更新中的任何一个出现错误,那么两者都会失败并被数据库回滚。
//inside async function
const disconnectPreviouslyConnectedFeatures = prisma.a_User.update({
where: {id: 1},
data: {
features: {
set: [] // disconnecting all previous features
}
}
})
const connectOrCreateNewFeatures = prisma.a_User.update({
where: {id: 1},
data: {
features: {
// connect or create the new features
connectOrCreate: [
{
where: {
description: "'first feature'"
}, create: {
description: "'first feature'"
}
},
{
where: {
description: "second feature"
}, create: {
description: "second feature"
}
}
]
}
}
})
// transaction to ensure either BOTH operations happen or NONE of them happen.
await prisma.$transaction([disconnectPreviouslyConnectedFeatures, connectOrCreateNewFeatures ])
如果您想更好地了解 connect
、disconnect
和 connectOrCreate
的工作原理,请阅读 Prisma Relation queries article 中的 嵌套写入 部分文档。
答案 1 :(得分:0)
prisma.a_User.update
的 TypeScript 定义可以准确地告诉您它需要哪些选项。这将告诉您发生 'features' does not exist in type
错误的原因。我想您传递给 data
的对象采用的选项集与您指定的选项不同;如果您可以检查 TypeScript 类型,Prisma 会准确地告诉您可用的选项。
如果您尝试添加新功能并更新特定功能,则需要指定 Prisma 如何找到旧功能(如果存在)来更新该功能。 Upsert 不会以您当前使用的方式工作;您需要为 upsert 调用提供某种标识符,以便确定您添加的功能是否已经存在。
https://www.prisma.io/docs/reference/api-reference/prisma-client-reference/#upsert
您至少需要 create
(如果特征不存在要传递什么数据)、update
(如果特征存在要传递什么数据)和 where
(如果特征不存在要传递什么数据) Prisma 可以找到您要更新或创建的功能。)
还需要多次调用upsert
;您要更新或创建的每个功能都有一个。在这种情况下,您可以将调用与 Promise.all
一起批处理。
const upsertFeature1Promise = prisma.a_User.update({
data: {
// upsert call goes here, with "create", "update", and "where"
}
});
const upsertFeature2Promise = prisma.a_User.update({
data: {
// upsert call goes here, with "create", "update", and "where"
}
});
const [results1, results2] = await Promise.all([
upsertFeaturePromise1,
upsertFeaturePromise2
]);