繁体   English   中英

使用具有一对一关系的 prisma 嵌套创建播种

[英]Seeding with prisma nested create with one-to-one relation

目前正在开展一个项目,以使用 nestjs 了解更多关于 prisma 的信息。 但不能让架构工作。 种子不会 go 通过,因为平面依赖于所有者字段,只能用创建的用户填充。

我想创建一个简单的数据库设置,其中用户可以是公寓的所有者,但必须拥有公寓。

一个公寓需要有一个所有者,并且可以有多个租户。

非常感谢这里的帮助,否则它只是另一个永远不会克服概念的项目。

架构:

model User {
  userId        String    @id @default(uuid())
  firstName     String?
  lastName      String?
  nickname      String
  email         String    @unique
  password      String
  phoneNumber   String?
  ownerOf       Flat?     @relation("owner")
  ownerOfId     String?   @unique
  flatId        String
  flat          Flat      @relation(fields: [flatId], references: [flatId])
  paidFor    Expense[] @relation("paidBy")
  otherExpenses Expense[]
  updatedAt     DateTime? @updatedAt
  createdAt     DateTime? @default(now())

  @@map("users")
}

model Flat {
  flatId    String    @id @default(uuid())
  name      String
  owner     User?      @relation("owner", fields: [ownerId], references: [userId])
  ownerId   String?    @unique
  flatmates User[]
  expenses  Expense[]
  updatedAt DateTime? @updatedAt
  createdAt DateTime? @default(now())

  @@map("flats")
}

model Expense {
  expenseId   String    @id @default(uuid())
  flatId      String
  flat        Flat      @relation(fields: [flatId], references: [flatId])
  paidBy   User      @relation("paidBy", fields: [paidById], references: [userId])
  paidById String
  expenseFor  User[]
  amount      Float
  updatedAt   DateTime? @updatedAt
  createdAt   DateTime? @default(now())

  @@map("expenses")
}
const users = await prisma.user.create({
    data: {
      firstName: 'Flo',
      lastName: 'Test',
      nickname: 'flo',
      email: 'test@test.de',
      password: hash,
      flat: {
        create: {
          name: 'Test Flat',
          owner: {
            connect: {
              users,
            },
          },
        },
      },
    },
  });

您需要先创建user ,然后在后续操作中connect flat 我会将其包装在交互式事务中。

我会开始考虑关系。

  • 公寓与租户之间的关系是什么? 现在是 1:n。 一套公寓可以有多个租户。 一个用户只能是一个单位的租户。
  • 公寓和业主之间是什么关系? 从您的架构来看,它是 1:1。 (您可能需要仔细检查。用户不能拥有多个公寓吗?)

附加要求是:

  • 用户必须是公寓的租户。
  • 公寓必须有所有者(来自您的问题文本)。 但是您的架构不需要那样。 这是一个关键点。

单位的owner仍然是可选的

您可以 model 这些关系在您的schema.prisma (简化)中像这样:

model User {
  userId    String @id @default(uuid())
  nickname  String
  flatId    String
  flat      Flat   @relation(fields: [flatId], references: [flatId], name: "tenantRelation")
  ownedFlat Flat?  @relation(name: "ownerRelation")

  @@map("users")
}

model Flat {
  flatId  String  @id @default(uuid())
  name    String
  ownerId String? @unique
  owner   User?   @relation(fields: [ownerId], references: [userId], name: "ownerRelation")
  tenants User[]  @relation(name: "tenantRelation")

  @@map("flats")
}

无需引入多余的User.ownerOfId

该模式不保证每个公寓都有一个所有者,因为ownerId是可选的。

如果你接受这个缺陷,你可以像这样创建用户和平面:

await prisma.user.create({
  data: { nickname: "flo", flat: { create: { name: "Test flat" } } },
});

然后在第二步中将公寓的所有者设置为用户...

公寓owner应该是强制性的

如果您不接受这个缺陷,并且将ownerId非可选,那么播种确实会变得更加困难,因为您有循环依赖。

在架构中,您只需删除两个问号:

model Flat {
  ...
  ownerId String @unique
  owner   User   @relation(fields: [ownerId], references: [userId], name: "ownerRelation")
  ...

然后,您必须:

  • 在数据库上设置外键DEFERRABLE INITIALLY DEFERREDDEFERRABLE INITIALLY IMMEDIATE 目前,prisma 无法做到这一点(参见: https://github.com/prisma/prisma/issues/8807 )。
  • 在同一个事务中执行原始查询,如下所示:
import { v4 as uuidv4 } from "uuid";

// ...

  const userId = uuidv4();
  const flatId = uuidv4();

  await prisma.$transaction(async ($tx) => {
    await $tx.$executeRaw`set constraints all deferred;`;
    await $tx.$executeRaw`INSERT INTO users ("userId", "nickname", "flatId") VALUES (${userId}, 'flo', ${flatId});`;
    await $tx.$executeRaw`INSERT INTO flats ("flatId", "name", "ownerId") VALUES (${flatId}, 'Test flat', ${userId});`;
  });

目前需要在您的schema.prisma中使用previewFeatures = ["interactiveTransactions"]

但在走这条路之前,我建议仔细检查您的应用程序将如何真正使用数据库。 用户和平面是否总是在同一步骤中创建?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM