在 Prisma 中创建或更新一对多关系

Ric*_*rdo 5 mysql typescript prisma

我正在尝试更新 Prisma 中的一对多关系。我的架构看起来像这样

model A_User {
  id            Int          @id
  username      String
  age           Int
  bio           String       @db.VarChar(1000)
  createdOn     DateTime     @default(now())
  features      A_Features[]
}

model A_Features {
  id       Int     @id @default(autoincrement())
  description    String
  A_User   A_User? @relation(fields: [a_UserId], references: [id])
  a_UserId Int?
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试向 id: 1 的用户添加一些新功能,或者更新它们(如果它们已经存在)。

我正在尝试做类似的事情

const post = await prisma.a_User.update({
        where: { id: 1},
        data: { 
            features: {
                upsert: [
                    { description: 'first feature'},
                    { description: 'second feature'}
                ]
            }
        }
    })
Run Code Online (Sandbox Code Playgroud)

编译器不高兴,它告诉我

Type '{ features: { upsert: { description: string; }[]; }; }' is not assignable to type '(Without<A_UserUpdateInput, A_UserUncheckedUpdateInput> & A_UserUncheckedUpdateInput) | (Without<...> & A_UserUpdateInput)'.
  Object literal may only specify known properties, and 'features' does not exist in type '(Without<A_UserUpdateInput, A_UserUncheckedUpdateInput> & A_UserUncheckedUpdateInput) | (Without<...> & A_UserUpdateInput)'.ts(2322)
index.d.ts(1572, 5): The expected type comes from property 'data' which is declared here on type '{ select?: A_UserSelect; include?: A_UserInclude; data: (Without<A_UserUpdateInput, A_UserUncheckedUpdateInput> & A_UserUncheckedUpdateInput) | (Without<...> & A_UserUpdateInput); where: A_UserWhereUniqueInput; }'
(property) features: {
    upsert: {
        description: string;
    }[];
}
Run Code Online (Sandbox Code Playgroud)

我无法弄清楚如何做到这一点,也无法在文档中找到明确的帮助。关于如何实现它或者我可以在哪里找到一些例子有什么想法吗?

Tas*_*mam 12

根据您在评论中提供的说明提供我的解决方案。首先,我将对您的架构进行以下更改。

更改架构

model A_User {
  id        Int          @id
  username  String
  age       Int
  bio       String       @db.VarChar(1000)
  createdOn DateTime     @default(now())
  features  A_Features[]
}

model A_Features {
  id          Int      @id @default(autoincrement())
  description String   @unique
  users       A_User[]
}
Run Code Online (Sandbox Code Playgroud)

A_User值得注意的是,和之间的关系A_Features现在是多对多的。因此,一条A_Features记录可以连接到许多A_User记录(反之亦然)。

此外,A_Features.description现在是唯一的,因此可以仅使用某个功能的描述来唯一地搜索该功能。

您可以阅读《Prisma 关系指南》以了解有关多对多关系的更多信息。

编写更新查询

同样,根据您在评论中提供的说明,更新操作将执行以下操作:

  • 覆盖现有features记录A_User。因此,之前的任何内容都features将被断开并替换为新提供的内容。请注意,前一个features不会从A_Features表中删除,但它们只会与 关系断开连接A_User.features

  • 创建表中尚不存在的新提供的特征A_Features,并连接表中已存在的提供的特征A_Features

您可以使用两个单独的update查询来执行此操作。第一次更新将断开features之前提供的所有连接A_User。第二个查询将连接或创建features表中新提供的内容A_Features。最后,您可以使用事务 API来确保这两个操作按顺序同时发生。事务 API 将确保如果两个更新中的任何一个出现错误,则两者都将失败并被数据库回滚。

model A_User {
  id        Int          @id
  username  String
  age       Int
  bio       String       @db.VarChar(1000)
  createdOn DateTime     @default(now())
  features  A_Features[]
}

model A_Features {
  id          Int      @id @default(autoincrement())
  description String   @unique
  users       A_User[]
}
Run Code Online (Sandbox Code Playgroud)

connect如果您想更好地了解,disconnect和 的工作原理connectOrCreate,请阅读文档中Prisma Relation 查询文章嵌套写入部分。

  • 这太棒了,您帮助我意识到我的方法出了什么问题,我将更深入地了解您链接的文档。感谢您为此付出的时间。 (2认同)

She*_*sky 1

的 TypeScript 定义prisma.a_User.update可以准确地告诉您它需要哪些选项。这会告诉您'features' does not exist in type错误发生的原因。我想您传递给的对象采用data与您指定的不同的选项集;如果您可以检查 TypeScript 类型,Prisma 会准确告诉您可用的选项。

如果您尝试添加新功能并更新特定功能,则需要指定 Prisma 如何找到旧功能(如果存在)来更新该功能。Upsert 不会按照您当前使用的方式工作;您需要向 upsert 调用提供某种标识符,以便确定您要添加的功能是否已存在。

https://www.prisma.io/docs/reference/api-reference/prisma-client-reference/#upsert

您至少需要create(如果该功能不存在,则传递哪些数据), update(如果该功能存在,则传递哪些数据),以及where(Prisma 如何找到您想要更新或创建的功能。)

还需要upsert多次调用;对应您想要更新或创建的每一项功能。在这种情况下,您可以将调用一起批处理Promise.all

const upsertFeature1Promise = prisma.a_User.update({
  data: {
    // upsert call goes here, with "create", "update", and "where"
  }
});
const upsertFeature2Promise = prisma.a_User.update({
  data: {
    // upsert call goes here, with "create", "update", and "where"
  }
});
const [results1, results2] = await Promise.all([
  upsertFeaturePromise1,
  upsertFeaturePromise2
]);
Run Code Online (Sandbox Code Playgroud)