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

如何在Prisma中用预定义ID实现1对1关联的嵌套写入?

预定义User ID时嵌套创建关联对象的问题解决

问题描述

需要创建带预定义ID的User,同时嵌套事务性创建关联的UserAuthentication和UserProfile,但TypeScript报错Type 'xxx' is not assignable to type 'never',且必须手动重复传入userId。

原Prisma Schema

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mongodb"
  url      = env("DATABASE_URL")
}

model User {
  id           String
  emailAddress String
  createdAt    DateTime @default(now())
  updatedAt    DateTime @default(now()) @updatedAt

  objectId String @id @default(auto()) @map("_id") @db.ObjectId

  profile UserProfile @relation(fields: [id], references: [userId])
  authentication UserAuthentication @relation(fields: [id], references: [userId])

  @@unique([id])
  @@unique([emailAddress])
  @@map("users")
}

model UserProfile {
  firstName    String
  lastName     String
  userId       String

  objectId String @id @default(auto()) @map("_id") @db.ObjectId

  user User?

  @@unique([userId])
  @@map("user-profiles")
}

model UserAuthentication {
  passwordHash String
  userId       String

  objectId String @id @default(auto()) @map("_id") @db.ObjectId

  user User?

  @@unique([userId])
  @@map("user-auths")
}

原代码实现

context.prisma.user
    .create({
      data: {
        id: userId,
        emailAddress: input.emailAddress.toLowerCase(),
        profile: {
          create: {
            userId,
            firstName: input.firstName,
            lastName: input.lastName
          }
        },
        authentication: {
          create: {
            userId,
            passwordHash
          }
        },
        createdAt,
        updatedAt: createdAt
      }
    })

解决方案

1. 修正Schema的关联定义

原Schema中反向关联(UserProfile.user、UserAuthentication.user)未明确指定关联关系,导致Prisma无法自动推断嵌套创建时的关联字段值。需要为反向关联补充@relation注解:

model UserProfile {
  firstName    String
  lastName     String
  userId       String

  objectId String @id @default(auto()) @map("_id") @db.ObjectId

  // 补充反向关联的@relation,指定关联字段映射
  user User @relation(fields: [userId], references: [id])

  @@unique([userId])
  @@map("user-profiles")
}

model UserAuthentication {
  passwordHash String
  userId       String

  objectId String @id @default(auto()) @map("_id") @db.ObjectId

  // 补充反向关联的@relation,指定关联字段映射
  user User @relation(fields: [userId], references: [id])

  @@unique([userId])
  @@map("user-auths")
}

2. 简化创建代码,移除重复的userId

关联定义正确后,Prisma会自动将User的id填充到关联对象的userId字段,无需手动传入:

context.prisma.user.create({
  data: {
    id: userId,
    emailAddress: input.emailAddress.toLowerCase(),
    profile: {
      create: {
        firstName: input.firstName,
        lastName: input.lastName
      }
    },
    authentication: {
      create: {
        passwordHash
      }
    },
    // 若无需自定义时间,可直接使用默认值,无需手动传入createdAt/updatedAt
    createdAt,
    updatedAt: createdAt
  }
})

关于重复传入userId的疑问

你的预期是正确的:只要Schema关联定义完整,Prisma会自动推断并填充关联字段的值,不需要手动重复传入userId。之前必须手动传是因为反向关联未正确定义,导致Prisma无法识别关联关系,进而无法自动填充。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 19:30:12