You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Prisma多对多关系中插入引用未存在记录的外键?

多对多关系建模:关联方不存在时的插入与查询解决方案

我需要建模一个多对多关系,但关联的其中一侧条目可能暂未存在。我最初用了如下Schema,但无法正常工作:

model Foo {
  id Int @id
}

model Bar {
  id Int @id
}

model FooBar {
  fooId Int
  barId Int

  foo Foo  @relation(fields: [fooId], references: [id])
  bar Bar? @relation(fields: [barId], references: [id])

  @@id([fooId, barId])
}

当尝试插入已存在的fooId: 1和暂未存在的barId: 1的关联时,触发了以下错误:

Type: undefined
Message:
Invalid prisma.fooBar.create() invocation:

An operation failed because it depends on one or more records that were required but not found. No 'Bar' record(s) (needed to inline the relation on 'fooBar' record(s)) was found for a nested connect on one-to-many relation 'fooBarToBar'.

Code: P2025

我需要一个可行方案:既能插入这种关联,又能在执行Foo查询{ include: { fooBar: { include: { bar: true }}}}时,在Bar不存在的情况下返回如下结构:

{
  "id": 1,
  "fooBar": {
    "fooId": 1,
    "barId": 1,
    "bar": null
  }
}

我试过上面的Schema但无效,猜测改成以下Schema能解决问题,但会产生冗余数据:

model FooBar {
  fooId Int
  barId Int

  barIdExisting Int?

  foo Foo  @relation(fields: [fooId], references: [id])
  bar Bar? @relation(fields: [barIdExisting], references: [id])
}

也就是仅当Bar存在时,将barIdExisting设为barId,但这样会造成数据冗余。


无冗余的正确解决方案

不需要冗余字段,只需把存储待关联Bar ID的普通字段和关联Bar表的外键字段拆分即可:

model Foo {
  id     Int     @id
  fooBar FooBar[]
}

model Bar {
  id     Int     @id
  fooBar FooBar[]
}

model FooBar {
  fooId         Int
  desiredBarId  Int  // 存储目标Bar的ID,无论该Bar是否存在
  barId         Int? // 可选外键,仅当Bar存在时赋值

  foo Foo   @relation(fields: [fooId], references: [id])
  bar Bar?  @relation(fields: [barId], references: [id])

  @@id([fooId, desiredBarId]) // 用fooId和desiredBarId作为复合主键
}

操作说明:

  • 插入关联:如果Bar不存在,只赋值fooId和desiredBarId,barId留空;如果Bar存在,可同时赋值fooId、desiredBarId和barId,或者通过connect关联对应的Bar记录。
  • 查询结果:执行你需要的查询语句后,当Bar不存在时,bar字段会返回null,同时desiredBarId保留你存储的目标ID,返回结构示例:
{
  "id": 1,
  "fooBar": [
    {
      "fooId": 1,
      "desiredBarId": 1,
      "barId": null,
      "bar": null
    }
  ]
}

原错误原因:

你最初的Schema把barId同时用作普通字段和外键,Prisma会强制外键关联的记录必须存在,因此当Bar不存在时无法插入。拆分字段后,desiredBarId仅存储ID值不做约束,barId作为可选外键仅在Bar存在时生效,既满足了存储未存在Bar的ID的需求,又避免了数据冗余。

内容的提问来源于stack exchange,提问作者darthmaim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 08:05:25