更新 Prisma 中的多对多关系
Posted
技术标签:
【中文标题】更新 Prisma 中的多对多关系【英文标题】:Updating many-to-many relations in Prisma 【发布时间】:2021-12-04 11:09:11 【问题描述】:我有一组针对皮肤问题的复选框。用户可以在提交前勾选/取消勾选,也就是说每次提交的皮肤问题集可能都不一样。
我在 Prisma 模式中将其建模为“显式”多对多关系。
model User
id String @id @default(cuid())
name String?
nickname String? @unique
...
skinConcerns SkinConcernsForUsers[]
...
model SkinConcern
id Int @id @default(autoincrement())
name String @unique
user SkinConcernsForUsers[]
model SkinConcernsForUsers
user User @relation(fields: [userId], references: [id])
userId String
skinConcern SkinConcern @relation(fields: [skinConcernId], references: [id])
skinConcernId Int
@@id([userId, skinConcernId])
然后,使用 prisma.skinConcern.createMany
为 SkinConcerns 表播种以下值:
"ACNE",
"DRYNESS",
"OILY_SKIN",
"PIGMENTATION",
"REDNESS",
"WRINKLES",
SkinConcerns
在更新变异输入中以字符串数组的形式出现,例如["PIGMENTATION", "REDNESS"]
.
我想通过 prisma.user.update
查询为用户 (SkinConcernsForUsers
) 更新皮肤问题,但这很棘手,因为我不仅要创建 SkinConcerns,而且还必须连接到现有的皮肤问题集。
我试过直接set
ting skinConcerns
in user
,喜欢
await prisma.user.update(
where: nickname ,
data:
// ... other user data
skinConcerns:
set: [
skinConcern:
connect: name: "PIGMENTATION" ,
,
,
skinConcern:
connect: name: "REDNESS" ,
,
,
],
,
// ... other user data
);
在许多其他事情中,但这当然不是一个正确的论点,并且会因错误而失败
Unknown arg `connect` in data.skinConcerns.update.0.where.connect for type SkinConcernsForUsersWhereUniqueInput. Did you mean `select`?
Argument data for data.skinConcerns.update.0.data is missing.
Unknown arg `connect` in data.skinConcerns.update.1.where.connect for type SkinConcernsForUsersWhereUniqueInput. Did you mean `select`?
Argument data for data.skinConcerns.update.1.data is missing.
有没有办法做到这一点?甚至可以在prisma.user.update
中更新它吗?
我想我可以直接更新SkinConcernsForUsers
。在这种情况下,我是否应该删除与用户关联但不在用户输入["PIGMENTATION", "REDNESS"]
中的所有行,然后创建不存在的行?它在棱镜代码中会是什么样子?
【问题讨论】:
【参考方案1】:首先,我会将您的架构更改为 SkinConcern
。 id
字段不是必需的,并且会在查询中造成复杂性(在尝试连接/断开记录时,您将不必要地需要将每个 name
映射到 id
。
name
字段足以作为主键,因为它对于某个记录始终是唯一的。
更改后的架构如下所示
model SkinConcern
name String @id // name is the new @id.
user SkinConcernsForUsers[]
model SkinConcernsForUsers
user User @relation(fields: [userId], references: [id])
userId String
skinConcern SkinConcern @relation(fields: [skinConcernName], references: [name])
skinConcernName String
@@id([userId, skinConcernName])
您想要执行的查询可以使用SkinConcernsForUsers
模型分两步执行。
第 1 步:删除用户连接到的现有 SkinConcernsForUsers
记录。这些不再相关,因为您想覆盖之前的选择。
第 2 步:使用新选项创建新的 SkinConcernsForUsers
记录。
这是代码的样子
// step 1
await prisma.skinConcernsForUsers.deleteMany(
where:
userId: "1",
,
);
// step 2
await prisma.skinConcernsForUsers.createMany(
data: [
userId: "1",
skinConcernName: "REDNESS",
,
userId: "1",
skinConcernName: "PIGMENTATION",
,
],
);
【讨论】:
谢谢!实际上,这是我在提出这个问题后立即想到的方法,并且我对使用字符串作为主键进行了一些研究。关于 SO 的一般建议是使用自动递增的整数 ID。我认为在我的情况下性能不是什么大问题,但我担心如果我将来必须更改这些键会很头疼(尽管我认为这不太可能)。无论如何,这将使我的工作变得简单得多,因此现在避免一些头痛可能比担心将来可能出现的头痛更好。 乐于助人:) 顺便说一下,对于另一个表,如果我绝对必须有一个整数 ID 作为主键和一个单独的名称列(如我原来的问题),我应该如何解决这个问题?跨度> 你需要某种映射到name_column
-> intenger_ID
。使用此映射,您可以找到对应的name_column
的integer_ID
(假设REDNESS 映射到ID 3)。然后,您更改查询以使用 integer_ID
字段代替 name_column
(对于我编写的示例查询,您可以将 skinConcernName
更改为 skinConcernId
)。
不幸的是,如果您在代码中手动编写它,就没有真正的方法来“保证”同步。我会考虑编写一个小型测试套件来验证数据是否与数据库同步。但正如我之前所说,如果记录数太多,这将非常难以管理,在这种情况下,我只需使用唯一的 name_column
查询数据库以找到匹配的 integer_ID
主键列。以上是关于更新 Prisma 中的多对多关系的主要内容,如果未能解决你的问题,请参考以下文章