Provide similar "connect" behavior when using explicit many-to-many tables compared to implicit tables
See original GitHub issueProblem
It would appear that when using explicit many-to-many tables, I am unable to use the connect
feature when creating an item since it is required to know both foreign keys to make the “connection”. Thus, I would like to be able to emulate the same behavior of an implicit join table when connecting an entity during a model.create()
with an explicit join table since you only need to provide the “known” foreign key during creation.
Given the following models defining an explicit table (taken from docs):
model Post {
id Int @id @default(autoincrement())
title String
categories CategoriesOnPosts[]
}
model Category {
id Int @id @default(autoincrement())
name String
posts CategoriesOnPosts[]
}
model CategoriesOnPosts {
post Post @relation(fields: [postId], references: [id])
postId Int // relation scalar field (used in the `@relation` attribute above)
category Category @relation(fields: [categoryId], references: [id])
categoryId Int // relation scalar field (used in the `@relation` attribute above)
@@id([postId, categoryId])
}
I would be unable to perform the following create
and connect
operation since an explicit many to many table requires that you know both foreign keys to make the connection
. Here’s a sample resolver displaying this issue:
async resolve(_root, args, ctx) {
const post = await ctx.db.post.create({
data: {
title: 'test title'
categories: {
connect: {
postId_categoryId: {
// I don't know this yet because the post hasn't been created, but typescript requires I add it,
postId: ???
categoryId: args.categoryId
}
},
},
},
})
For example, if I had an implicit table I could just do:
const post = await ctx.db.post.create({
data: {
title: 'my title,
categories: {
connect: {
// this doesn't require the postId but adds it when making the join table
id: args.categoryId,
},
},
},
})
Suggested solution
Provide the ability to add just the “known” foreign key when connecting an element to a new item, similar to the implicit many to many join tables:
async resolve(_root, args, ctx) {
const post = await ctx.db.post.create({
data: {
title: 'test title'
categories: {
connect: {
postId_categoryId: {
// only require the "known" id
categoryId: args.categoryId
}
},
},
},
})
Issue Analytics
- State:
- Created 3 years ago
- Reactions:17
- Comments:13 (2 by maintainers)
@janpio I can confirm this is not a bug, but a documentation issue.
Assuming the following schema:
This succeeds:
I change the schema to use an explicit many-to-many relationship:
The previous
create
fails, but this one succeeds:connectOrCreate
succeeds as well.I think this difference should be described in more detail in the docs.
EDIT: Do not use this, real solution below!
Until this is implemented, I found a workaround.
Schema:
It’s a mix of explicit and implicit. I’m defining an explicit many-to-many relationship, while mapping it onto the implicit one. This allows me to define additional fields on the junction table, use connect, e.t.c. The only drawback I found so far (apart from the ugly names when working directly with the junction table) is that I have to run
prisma db push
twice on an empty database. It fails the first time and succeeds the second time. It’s not pretty but it will do until this is supported by Prisma.