外部表
概述
Prisma ORM 中的外部托管表(或简称外部表)是指可以通过 Prisma Client 查询但被 Prisma Migrate 忽略的表。
有时,您可能不希望 Prisma ORM 管理特定的表——例如由另一个团队或服务处理的表。
以下是一些具体的用例:
- auth 服务,如 Clerk 或 Auth0,它们管理包含用户和会话数据的特定表
- 存储服务,如 Supabase Storage,其中包含用于存储桶和对象元数据的表
- 基于微服务的组织,其中特定团队拥有数据库中的特定表
根据自定义组织约束或偏好,可能还有许多其他场景,您可能不希望 Prisma ORM 管理特定表。
外部托管表目前处于预览阶段。
外部托管表通常与多模式数据库设置结合使用。然而,这并非硬性要求。您的数据库中可以只有一个模式,并在其中声明外部托管表。
Prisma ORM 不会验证数据库中表的结构与 Prisma 模型结构是否实际匹配。一方面,这要求开发人员在更新 Prisma 模式时要彻底(最安全的方法是使用 prisma db pull)。另一方面,这种灵活性使您能够仅表示数据库中底层表的一部分(例如,不公开所有列)。
工作流程
如果您想使用外部表,这是主要的工作流程
- 在您的 Prisma 配置文件中声明外部表的名称
- 更新您的 Prisma 模式(例如,通过
npx prisma db pull) - 使用
npx prisma generate重新生成 Prisma Client - 您现在可以使用 Prisma Client 查询外部表,但它将被 Prisma Migrate 忽略
- 当表被更改时(由其所有者)
- 使用
npx prisma db pull重新内省您的数据库,或手动更新 prisma 文件中的模型 - 使用
npx prisma generate重新生成 Prisma Client
- 使用
Prisma 配置语法
您可以通过 tables.external 属性在您的 Prisma 配置文件中指定外部托管表
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.products或auth.users。 - 在 MySQL 和 SQLite 上,您只需指定表名称。
关系
Prisma 可以创建和更新它管理的表与外部托管表之间的关系。
但是,为此,Prisma 需要在迁移创建期间了解这些外部托管表的结构。您可以提供一个 SQL 脚本,Prisma 将在其影子数据库上运行,先于所有迁移,以便在迁移创建期间模拟外部表和枚举。
创建的占位符表不需要具有实际表的完整结构,但必须存在主键。
如果外部表没有被任何托管表引用——也就是说,没有托管表包含对外部表的外键约束——您在 migrations.initShadowDb 中不需要为其提供任何 SQL。
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 属性启用外部托管表的使用
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 表。
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 命令。