【问题标题】:Prisma 'set' with explicit many-to-many relation?具有明确的多对多关系的棱镜“集合”?
【发布时间】:2026-01-03 02:45:02
【问题描述】:

正如在 Prisma 的 document 中一样,set 可用于覆盖关系的值。

const user = await prisma.user.update({
  where: { email: 'alice@prisma.io' },
  data: {
    posts: {
      set: [{ id: 32 }, { id: 42 }],
    },
  },
})

但是当我尝试使用明确的多对多关系时,它不起作用。

model Product {
  id        String   @id @default(cuid())
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt

  name        String
  description String?
  price       Decimal
  sku         String  @unique
  published   Boolean @default(false)

  tags ProductTag[]
}

model Tag {
  id   Int    @id @default(autoincrement())
  name String

  products ProductTag[]
}

model ProductTag {
  productId String
  tagId     Int

  createdAt DateTime @default(now())

  product Product @relation(fields: [productId], references: [id])
  tag     Tag     @relation(fields: [tagId], references: [id])

  @@id([productId, tagId])
}

我的代码要更新Product

update(id: string, updateProductDto: UpdateProductDto) {
    const tags = updateProductDto.tags.map((tag) => ({
      productId_tagId: {
        productId: id,
        tagId: tag.id,
      },
    }));

    console.log(JSON.stringify(tags));

    return this.prisma.product.update({
      where: { id: id },
      data: {
        ...updateProductDto,
        tags: {
          set: [...tags],
        },
      },
    });
  }

我想用产品信息更新产品标签。

我怎样才能正确地实现它?

【问题讨论】:

  • 请提供错误消息,以及来自 node_modules/.prisma/client/index.d.ts 的 ProductTagWhereUniqueInput

标签: typescript orm prisma prisma2


【解决方案1】:

我尝试回复,但我会要求您添加错误消息,以及来自 node_modules/.prisma/client/index.d.ts 的 ProductTagWhereUniqueInput

update(id: string, updateProductDto: UpdateProductDto) {
    const tags = updateProductDto.tags.map((tag) => ({
        // no need to encapsulate  
        productId: id,
        tagId: tag.id,
    }));
     // prevent the tags property to be update in product table, because you want to use set. 
    delete updateProductDto.tags;

    console.log(JSON.stringify(tags));

    return this.prisma.product.update({
      where: { id: id },
      data: {
        ...updateProductDto,
        tags: {
          set: tags, // no need to rebuild the array
        },
      },
    });
  }

【讨论】:

  • 我已经复制了你的代码,但是'set'的类型是无效的。所以我认为它必须被封装。
【解决方案2】:

您可以删除现有的productTag 记录,然后在两个单独的查询中创建新记录。然后你可以将这两个查询作为一个事务运行。

这就是它的样子

    // do other updates to Tags with values from updateProductDto. 

    const deleteOldtags = prisma.productTag.deleteMany({
        where: { productId: "__PRODUCT_ID__" },
    });

    const addNewTags = prisma.productTag.createMany({
        data: [
            {
                productId: "__PRODUCT_ID__",
                tagId: TAG_ID_VALUE

            },
            // ...array of productID and tagId objects. 
        ]
    })

    let updateTags = await prisma.$transaction([deleteOldtags, addNewTags])

这是一种解决方法,与set 略有不同,因为它每次都会创建新记录。

【讨论】:

  • 这可能也是我能想到的唯一方法。如果没有更好的答案,我会将其标记为答案。
  • 这不会更新关系,它会创建新的对象,这是完全不同的行为。
  • @RomainTAILLANDIER 是的,它会创建新对象,但这是解决此问题的方法。