跳至主要内容

外部表

概述

Prisma ORM 中的外部托管表(或简称外部表)是指可以通过 Prisma Client 查询被 Prisma Migrate 忽略的表。

有时,您可能不希望 Prisma ORM 管理特定的表——例如由另一个团队或服务处理的表。

以下是一些具体的用例:

  • auth 服务,如 Clerk 或 Auth0,它们管理包含用户和会话数据的特定表
  • 存储服务,如 Supabase Storage,其中包含用于存储桶和对象元数据的表
  • 基于微服务的组织,其中特定团队拥有数据库中的特定表

根据自定义组织约束或偏好,可能还有许多其他场景,您可能不希望 Prisma ORM 管理特定表。

警告

外部托管表目前处于预览阶段。

注意

外部托管表通常与多模式数据库设置结合使用。然而,这并非硬性要求。您的数据库中可以只有一个模式,并在其中声明外部托管表。

警告

Prisma ORM 不会验证数据库中表的结构与 Prisma 模型结构是否实际匹配。一方面,这要求开发人员在更新 Prisma 模式时要彻底(最安全的方法是使用 prisma db pull)。另一方面,这种灵活性使您能够仅表示数据库中底层表的一部分(例如,不公开所有列)。

工作流程

如果您想使用外部表,这是主要的工作流程

  1. 在您的 Prisma 配置文件中声明外部表的名称
  2. 更新您的 Prisma 模式(例如,通过 npx prisma db pull
  3. 使用 npx prisma generate 重新生成 Prisma Client
  4. 您现在可以使用 Prisma Client 查询外部表,但它将被 Prisma Migrate 忽略
  5. 当表被更改时(由其所有者)
    1. 使用 npx prisma db pull 重新内省您的数据库,或手动更新 prisma 文件中的模型
    2. 使用 npx prisma generate 重新生成 Prisma Client

Prisma 配置语法

您可以通过 tables.external 属性在您的 Prisma 配置文件中指定外部托管表

prisma.config.ts
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'

export default defineConfig({
schema: 'prisma/schema.prisma',
migrations: {
path: 'prisma/migrations',
},
datasource: {
url: env('DATABASE_URL'),
},
// required when using unstable features
experimental: {
externalTables: true
},
// declare the `users` table and `role` enum as external
tables: {
external: [
"public.users",
]
},
enums: {
external: [
"public.role",
]
},
})
  • 与表类似,您也可以拥有外部托管的枚举
  • 在 PostgreSQL 和 SQL Server 上,您必须指定完全限定的表/枚举名称,包括模式名称。例如:public.productsauth.users
  • 在 MySQL 和 SQLite 上,您只需指定表名称。

关系

Prisma 可以创建和更新它管理的表与外部托管表之间的关系。

但是,为此,Prisma 需要在迁移创建期间了解这些外部托管表的结构。您可以提供一个 SQL 脚本,Prisma 将在其影子数据库上运行,先于所有迁移,以便在迁移创建期间模拟外部表和枚举。

创建的占位符表不需要具有实际表的完整结构,但必须存在主键。

如果外部表没有被任何托管表引用——也就是说,没有托管表包含对外部表的外键约束——您在 migrations.initShadowDb 中不需要为其提供任何 SQL。

prisma.config.ts
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'

export default defineConfig({
schema: 'prisma/schema.prisma',
datasource: {
url: env('DATABASE_URL'),
},
// required when using unstable features
experimental: {
externalTables: true
},
// declare a `users` table
tables: {
external: [
"public.users",
]
},
migrations: {
path: 'prisma/migrations',
// setup the users table for the shadow database
initShadowDb: `
CREATE TABLE public.users (id SERIAL PRIMARY KEY);
`
},
})

从外部表到托管表的关系,其中外部表包含对托管表的外键约束,由 Prisma 管理,因为那会修改外部表。

示例

假设您有以下 Prisma 模式,其中只包含 posts

generator client {
provider = "prisma-client"
output = "./generated"
// ...
}

datasource db {
provider = "postgresql"
// ...
}

model posts {
id Int @id @default(autoincrement())
created_at DateTime @default(now())
title String
content String?
}

您已经通过之前的迁移创建了 posts 表。现在您的数据库中还有一个 users 表和 role 枚举,您希望将其视为外部托管。

因此,您的 PostgreSQL 数据库中默认 public 模式下的表如下所示

-- Enum used by users table
CREATE TYPE role AS ENUM ('customer', 'support', 'admin');

-- Users table
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
role role
);

-- Posts table
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
title VARCHAR(200) NOT NULL,
content TEXT
);

1. 在 Prisma 配置中声明外部托管表

通过 tables.external 属性启用外部托管表的使用

prisma.config.ts
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'

export default defineConfig({
schema: 'prisma/schema.prisma',
migrations: {
path: 'prisma/migrations',
},
datasource: {
url: env('DATABASE_URL'),
},
experimental: {
externalTables: true
},
// declare the `users` table and `role` enum as external
tables: {
external: [
"public.users",
]
},
enums: {
external: [
"public.role",
]
},
})

2. 更新 Prisma 模式

接下来,您需要更新您的 Prisma 模式。您可以选择以下两种方式:

  • 手动创建模型
  • 或使用内省
npx prisma db pull

users 表现在已在您的 Prisma 模式中

model posts {
id Int @id @default(autoincrement())
created_at DateTime? @default(now()) @db.Timestamp(6)
title String @db.VarChar(200)
content String?
}

model users {
id Int @id @default(autoincrement())
username String @unique @db.VarChar(50)
email String @unique @db.VarChar(100)
created_at DateTime? @default(now()) @db.Timestamp(6)
role role
}

enum role {
customer
support
admin
}

3. 重新生成 Prisma Client

为了能够查询 users 表,您需要重新生成 Prisma Client

npx prisma generate

4. 使用 Prisma Client 查询 users

您现在可以使用 Prisma Client 查询外部 users

await prisma.users.findMany()

5. 添加关系

假设您现在想从 posts 添加一个作者关系到 users

首先更新您的 Prisma 模式。

model posts {
id Int @id @default(autoincrement())
created_at DateTime? @default(now()) @db.Timestamp(6)
title String @db.VarChar(200)
content String?
author users @relation(fields: [author_id], references: [id])
author_id Int
}

model users {
id Int @id @default(autoincrement())
username String @unique @db.VarChar(50)
email String @unique @db.VarChar(100)
created_at DateTime? @default(now()) @db.Timestamp(6)
role role
posts posts[]
}

enum role {
customer
support
admin
}

然后添加一个 migrations.initShadowDb 脚本,以便 Prisma 在迁移期间了解 users 表。

prisma.config.ts
import 'dotenv/config'
import { defineConfig, env } from 'prisma/config'

export default defineConfig({
schema: 'prisma/schema.prisma',
datasource: {
url: env('DATABASE_URL'),
},
experimental: {
externalTables: true
},
tables: {
external: [
"public.users",
]
},
migrations: {
path: 'prisma/migrations',
// setup the users table for the shadow database
initShadowDb: `
CREATE TABLE public.users (id SERIAL PRIMARY KEY);
`
},
})

现在您可以运行 prisma migrate dev 命令。

© . This site is unofficial and not affiliated with Prisma Data, Inc.