模型
Prisma schema 的数据模型定义部分定义了您的应用程序模型(也称为 Prisma 模型)。模型
- 代表您的应用领域的实体
- 映射到数据库中的表(关系数据库,如 PostgreSQL)或集合(MongoDB)
- 构成生成的 Prisma Client API 中可用查询的基础
- 与 TypeScript 一起使用时,Prisma Client 为您的模型及其任何变体提供生成的类型定义,以使数据库访问完全类型安全。
以下 schema 描述了一个博客平台 - 数据模型定义已高亮显示
- 关系型数据库
- MongoDB
datasource db {
provider = "postgresql"
}
generator client {
provider = "prisma-client"
output = "./generated"
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
role Role @default(USER)
posts Post[]
profile Profile?
}
model Profile {
id Int @id @default(autoincrement())
bio String
user User @relation(fields: [userId], references: [id])
userId Int @unique
}
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
title String
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
categories Category[]
}
model Category {
id Int @id @default(autoincrement())
name String
posts Post[]
}
enum Role {
USER
ADMIN
}
datasource db {
provider = "mongodb"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String @unique
name String?
role Role @default(USER)
posts Post[]
profile Profile?
}
model Profile {
id String @id @default(auto()) @map("_id") @db.ObjectId
bio String
user User @relation(fields: [userId], references: [id])
userId String @unique @db.ObjectId
}
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
createdAt DateTime @default(now())
title String
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId String @db.ObjectId
categoryIDs String[] @db.ObjectId
categories Category[] @relation(fields: [categoryIDs], references: [id])
}
model Category {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String
postIDs String[] @db.ObjectId
posts Post[] @relation(fields: [postIDs], references: [id])
}
enum Role {
USER
ADMIN
}
数据模型定义由以下部分组成
相应的数据库如下所示

模型映射到数据源的底层结构。
- 在 PostgreSQL 和 MySQL 等关系数据库中,
model映射到表 - 在 MongoDB 中,
model映射到集合
注意:将来可能会有非关系数据库和其他数据源的连接器。例如,对于 REST API,它将映射到资源。
以下查询使用从该数据模型生成的 Prisma Client 来创建
- 一个
User记录 - 两个嵌套的
Post记录 - 三个嵌套的
Category记录
- 查询示例
- 复制粘贴示例
const user = await prisma.user.create({
data: {
email: 'ariadne@prisma.io',
name: 'Ariadne',
posts: {
create: [
{
title: 'My first day at Prisma',
categories: {
create: {
name: 'Office',
},
},
},
{
title: 'How to connect to a SQLite database',
categories: {
create: [{ name: 'Databases' }, { name: 'Tutorials' }],
},
},
],
},
},
})
import { PrismaClient } from '../prisma/generated/client'
const prisma = new PrismaClient({})
// A `main` function so that you can use async/await
async function main() {
// Create user, posts, and categories
const user = await prisma.user.create({
data: {
email: 'ariadne@prisma.io',
name: 'Ariadne',
posts: {
create: [
{
title: 'My first day at Prisma',
categories: {
create: {
name: 'Office',
},
},
},
{
title: 'How to connect to a SQLite database',
categories: {
create: [{ name: 'Databases' }, { name: 'Tutorials' }],
},
},
],
},
},
})
// Return user, and posts, and categories
const returnUser = await prisma.user.findUnique({
where: {
id: user.id,
},
include: {
posts: {
include: {
categories: true,
},
},
},
})
console.log(returnUser)
}
main()
您的数据模型反映了您的应用领域。例如
- 在电子商务应用中,您可能有
Customer、Order、Item和Invoice等模型。 - 在社交媒体应用中,您可能有
User、Post、Photo和Message等模型。
内省和迁移
有两种定义数据模型的方法
- 手动编写数据模型并使用 Prisma Migrate:您可以手动编写数据模型,并使用 Prisma Migrate 将其映射到数据库。在这种情况下,数据模型是您应用程序模型的单一事实来源。
- 通过内省生成数据模型:当您有一个现有数据库或更喜欢使用 SQL 迁移数据库 schema 时,您可以通过内省数据库来生成数据模型。在这种情况下,数据库 schema 是您应用程序模型的单一事实来源。
定义模型
模型代表您的应用领域的实体。模型由 model 块表示,并定义了许多字段。在上面的示例数据模型中,User、Profile、Post 和 Category 都是模型。
博客平台可以通过以下模型进行扩展
model Comment {
// Fields
}
model Tag {
// Fields
}
将模型名称映射到表或集合
Prisma 模型命名约定(单数形式,PascalCase)并不总是与数据库中的表名匹配。在数据库中命名表/集合的常见方法是使用复数形式和 snake_case 符号 - 例如:comments。当您内省一个名为 comments 的表时,结果 Prisma 模型将如下所示
model comments {
// Fields
}
但是,您仍然可以通过使用 @@map 属性来遵守命名约定,而无需重命名数据库中底层的 comments 表
model Comment {
// Fields
@@map("comments")
}
通过此模型定义,Prisma ORM 自动将 Comment 模型映射到底层数据库中的 comments 表。
注意:您还可以
@map字段名或枚举值,以及@@map枚举名。
@map 和 @@map 允许您通过将模型和字段名称与底层数据库中的表和列名称解耦来调整 Prisma Client API 的形状。
定义字段
模型的属性称为字段,它由以下部分组成
字段的类型决定其结构,分为以下两类之一
- 标量类型(包括枚举),它们映射到数据库中的列(关系数据库)或文档字段(MongoDB) - 例如,
String或Int - 模型类型(该字段随后称为关系字段) - 例如
Post或Comment[]。
下表描述了示例 schema 中 User 模型的字段
展开以查看表格
| 名称 | 类型 | 标量与关系 | 类型修饰符 | 属性 |
|---|---|---|---|---|
id | Int | 标量 | - | @id 和 @default(autoincrement()) |
电子邮件 | String | 标量 | - | @unique |
名称 | String | 标量 | ? | - |
角色 | 角色 | 标量(enum) | - | @default(USER) |
帖子 | 帖子 | 关系(Prisma 级别字段) | [] | - |
个人资料 | 个人资料 | 关系(Prisma 级别字段) | ? | - |
标量字段
以下示例使用多个标量类型扩展了 Comment 和 Tag 模型。某些字段包含属性
- 关系型数据库
- MongoDB
model Comment {
id Int @id @default(autoincrement())
title String
content String
}
model Tag {
name String @id
}
model Comment {
id String @id @default(auto()) @map("_id") @db.ObjectId
title String
content String
}
model Tag {
name String @id @map("_id")
}
请参阅标量字段类型的完整列表。
关系字段
关系字段的类型是另一个模型 - 例如,一个帖子(Post)可以有多个评论(Comment[])
- 关系型数据库
- MongoDB
model Post {
id Int @id @default(autoincrement())
// Other fields
comments Comment[] // A post can have many comments
}
model Comment {
id Int
// Other fields
post Post? @relation(fields: [postId], references: [id]) // A comment can have one post
postId Int?
}
model Post {
id String @id @default(auto()) @map("_id") @db.Objectid
// Other fields
comments Comment[] // A post can have many comments
}
model Comment {
id String @id @default(auto()) @map("_id") @db.Objectid
// Other fields
post Post? @relation(fields: [postId], references: [id]) // A comment can have one post
postId String? @db.ObjectId
}
有关更多示例以及模型之间关系的信息,请参阅关系文档。
原生类型映射
版本 2.17.0 及更高版本支持原生数据库类型属性(类型属性),它们描述了底层数据库类型
model Post {
id Int @id
title String @db.VarChar(200)
content String
}
类型属性具有以下特点
- 特定于底层提供者 - 例如,PostgreSQL 使用
@db.Boolean表示Boolean,而 MySQL 使用@db.TinyInt(1) - 以 PascalCase 编写(例如,
VarChar或Text) - 前缀为
@db,其中db是 schema 中datasource块的名称
此外,在内省期间,只有当底层原生类型不是默认类型时,才将类型属性添加到 schema 中。例如,如果您使用 PostgreSQL 提供者,底层原生类型为 text 的 String 字段将没有类型属性。
优点和工作流程
- 控制 Prisma Migrate 在数据库中创建的确切原生类型 - 例如,
String可以是@db.VarChar(200)或@db.Char(50) - 内省时查看丰富的 schema
类型修饰符
字段的类型可以通过附加以下两种修饰符之一来修改
注意:您不能组合类型修饰符 - 不支持可选列表。
列表
以下示例包含一个标量列表和一个相关模型列表
- 关系型数据库
- MongoDB
model Post {
id Int @id @default(autoincrement())
// Other fields
comments Comment[] // A list of comments
keywords String[] // A scalar list
}
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
// Other fields
comments Comment[] // A list of comments
keywords String[] // A scalar list
}
注意:仅当数据库连接器支持标量列表时(无论是原生支持还是在 Prisma ORM 级别支持),才支持标量列表。
可选字段和必填字段
- 关系型数据库
- MongoDB
model Comment {
id Int @id @default(autoincrement())
title String
content String?
}
model Tag {
name String @id
}
model Comment {
id String @id @default(auto()) @map("_id") @db.ObjectId
title String
content String?
}
model Tag {
name String @id @map("_id")
}
当字段不使用 ? 类型修饰符进行注释时,该字段对于模型的每条记录都是必需的。这在两个层面产生影响
- 数据库
- 关系数据库:必需字段通过底层数据库中的
NOT NULL约束表示。 - MongoDB:必需字段在 MongoDB 数据库级别上不是一个概念。
- 关系数据库:必需字段通过底层数据库中的
- Prisma Client:Prisma Client 生成的 TypeScript 类型,它们代表您应用程序代码中的模型,也会将这些字段定义为必需,以确保它们在运行时始终具有值。
注意:可选字段的默认值为
null。
不支持的类型
当您内省关系数据库时,不支持的数据类型将作为 Unsupported 添加
location Unsupported("POLYGON")?
Unsupported 类型允许您在 Prisma schema 中定义 Prisma ORM 尚不支持的数据库类型的字段。例如,MySQL 的 POLYGON 类型目前不受 Prisma ORM 支持,但现在可以使用 Unsupported("POLYGON") 类型添加到 Prisma schema 中。
类型为 Unsupported 的字段不会出现在生成的 Prisma Client API 中,但您仍然可以使用 Prisma ORM 的原始数据库访问功能来查询这些字段。
注意:如果模型具有必需的
Unsupported字段,则生成的客户端将不包含该模型的create或update方法。
注意:MongoDB 连接器不支持也不需要
Unsupported类型,因为它支持所有标量类型。
定义属性
属性修改字段或模型块的行为。以下示例包含三个字段属性(@id、@default 和 @unique)和一个块属性(@@unique)
- 关系型数据库
- MongoDB
model User {
id Int @id @default(autoincrement())
firstName String
lastName String
email String @unique
isAdmin Boolean @default(false)
@@unique([firstName, lastName])
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
firstName String
lastName String
email String @unique
isAdmin Boolean @default(false)
@@unique([firstName, lastName])
}
某些属性接受参数 - 例如,@default 接受 true 或 false
isAdmin Boolean @default(false) // short form of @default(value: false)
请参阅字段和块属性的完整列表
定义 ID 字段
ID 唯一标识模型的单个记录。一个模型只能有一个 ID
- 在关系数据库中,ID 可以是单个字段或基于多个字段。如果模型没有
@id或@@id,则必须定义一个必需的@unique字段或@@unique块来代替。 - 在MongoDB中,ID 必须是定义
@id属性和@map("_id")属性的单个字段。
在关系数据库中定义 ID
在关系数据库中,ID 可以通过使用 @id 属性的单个字段定义,或者通过使用 @@id 属性的多个字段定义。
单个字段 ID
在以下示例中,User ID 由 id 整数字段表示
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
role Role @default(USER)
posts Post[]
profile Profile?
}
复合 ID
在以下示例中,User ID 由 firstName 和 lastName 字段的组合表示
model User {
firstName String
lastName String
email String @unique
isAdmin Boolean @default(false)
@@id([firstName, lastName])
}
默认情况下,此字段在 Prisma Client 查询中的名称将是 firstName_lastName。
您还可以使用 @@id 属性的 name 字段为复合 ID 提供自己的名称
model User {
firstName String
lastName String
email String @unique
isAdmin Boolean @default(false)
@@id(name: "fullName", fields: [firstName, lastName])
}
firstName_lastName 字段现在将命名为 fullName。
请参阅有关使用复合 ID 的文档,以了解如何在 Prisma Client 中与复合 ID 进行交互。
作为唯一标识符的 @unique 字段
在以下示例中,用户由 @unique 字段唯一标识。因为 email 字段作为模型的唯一标识符(这是必需的),它必须是强制性的
model User {
email String @unique
name String?
role Role @default(USER)
posts Post[]
profile Profile?
}
关系数据库中的约束名称
您可以选择在底层数据库中定义自定义主键约束名称。
在 MongoDB 中定义 ID
MongoDB 连接器具有定义 ID 字段的特定规则,这与关系数据库不同。ID 必须通过使用 @id 属性的单个字段定义,并且必须包含 @map("_id")。
在以下示例中,User ID 由接受自动生成的 ObjectId 的 id 字符串字段表示
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String @unique
name String?
role Role @default(USER)
posts Post[]
profile Profile?
}
在以下示例中,User ID 由接受 ObjectId 以外的东西的 id 字符串字段表示 - 例如,唯一的用户名
model User {
id String @id @map("_id")
email String @unique
name String?
role Role @default(USER)
posts Post[]
profile Profile?
}
MongoDB 不支持 @@id
MongoDB 不支持复合 ID,这意味着您不能使用 @@id 块来标识模型。
定义默认值
您可以使用 @default 属性为模型的标量字段定义默认值
- 关系型数据库
- MongoDB
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
title String
published Boolean @default(false)
data Json @default("{ \"hello\": \"world\" }")
author User @relation(fields: [authorId], references: [id])
authorId Int
categories Category[] @relation(references: [id])
}
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
createdAt DateTime @default(now())
title String
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId String @db.ObjectId
categories Category[] @relation(references: [id])
}
@default 属性要么
- 表示底层数据库中的
DEFAULT值(仅限关系数据库)或 - 使用 Prisma ORM 级别函数。例如,
cuid()和uuid()由 Prisma Client 的查询引擎为所有连接器提供。
默认值可以是
- 与字段类型对应的静态值,例如
5(Int)、Hello(String) 或false(Boolean) - 静态值列表,例如
[5, 6, 8](Int[]) 或["Hello", "Goodbye"](String[])。这些在 Prisma ORM4.0.0及更高版本中可用,当使用支持的数据库(PostgreSQL、CockroachDB 和 MongoDB)时 - 函数,例如
now()或uuid() - JSON 数据。请注意,JSON 需要在
@default属性中用双引号括起来,例如:@default("[]")。如果您想提供一个 JSON 对象,您需要用双引号括起来,然后使用反斜杠转义任何内部双引号,例如:@default("{ \"hello\": \"world\" }")。
有关连接器对函数的支持信息,请参阅属性函数参考文档。
定义唯一字段
您可以向模型添加唯一属性,以便能够唯一标识该模型的单个记录。唯一属性可以在单个字段上使用 @unique 属性定义,也可以在多个字段上(也称为复合或组合唯一约束)使用 @@unique 属性定义。
在以下示例中,email 字段的值必须是唯一的
- 关系型数据库
- MongoDB
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String @unique
name String?
}
在以下示例中,authorId 和 title 的组合必须是唯一的
- 关系型数据库
- MongoDB
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
title String
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
categories Category[] @relation(references: [id])
@@unique([authorId, title])
}
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
createdAt DateTime @default(now())
title String
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId String @db.ObjectId
categories Category[] @relation(references: [id])
@@unique([authorId, title])
}
关系数据库中的约束名称
您可以选择在底层数据库中定义自定义唯一约束名称。
默认情况下,此字段在 Prisma Client 查询中的名称将是 authorId_title。
您还可以使用 @@unique 属性的 name 字段为复合唯一约束提供自己的名称
model Post {
id String @id @default(auto()) @map("_id") @db.ObjectId
createdAt DateTime @default(now())
title String
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId String @db.ObjectId
categories Category[] @relation(references: [id])
@@unique(name: "authorTitle", [authorId, title])
}
authorId_title 字段现在将命名为 authorTitle。
请参阅有关使用复合唯一标识符的文档,以了解如何在 Prisma Client 中与复合唯一约束进行交互。
复合类型唯一约束
当在版本 3.12.0 及更高版本中使用 MongoDB 提供者时,您可以使用语法 @@unique([compositeType.field]) 在复合类型的字段上定义唯一约束。与其他字段一样,复合类型字段可以用作多列唯一约束的一部分。
以下示例定义了一个基于 User 模型的 email 字段和 Address 复合类型的 number 字段的多列唯一约束,该复合类型用于 User.address
type Address {
street String
number Int
}
model User {
id Int @id
email String
address Address
@@unique([email, address.number])
}
如果有多个嵌套复合类型,此符号可以链式使用
type City {
name String
}
type Address {
number Int
city City
}
model User {
id Int @id
address Address[]
@@unique([address.city.name])
}
定义索引
您可以通过模型上的 @@index 在模型的单个或多个字段上定义索引。以下示例定义了一个基于 title 和 content 字段的多列索引
model Post {
id Int @id @default(autoincrement())
title String
content String?
@@index([title, content])
}
关系数据库中的索引名称
您可以选择在底层数据库中定义自定义索引名称。
定义复合类型索引
当在版本 3.12.0 及更高版本中使用 MongoDB 提供者时,您可以使用语法 @@index([compositeType.field]) 在复合类型的字段上定义索引。与其他字段一样,复合类型字段可以用作多列索引的一部分。
以下示例定义了一个基于 User 模型的 email 字段和 Address 复合类型的 number 字段的多列索引
type Address {
street String
number Int
}
model User {
id Int @id
email String
address Address
@@index([email, address.number])
}
如果有多个嵌套复合类型,此符号可以链式使用
type City {
name String
}
type Address {
number Int
city City
}
model User {
id Int @id
address Address[]
@@index([address.city.name])
}
定义枚举
如果您的数据库连接器支持枚举(无论是原生支持还是在 Prisma ORM 级别支持),您可以在数据模型中定义枚举。
枚举在 Prisma schema 数据模型中被视为标量类型。因此,它们默认情况下包含在 Prisma Client 查询的返回值中。
枚举通过 enum 块定义。例如,一个 User 有一个 Role
- 关系型数据库
- MongoDB
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
role Role @default(USER)
}
enum Role {
USER
ADMIN
}
model User {
id String @id @default(auto()) @map("_id") @db.ObjectId
email String @unique
name String?
role Role @default(USER)
}
enum Role {
USER
ADMIN
}
定义复合类型
复合类型在版本 3.10.0 中以 mongodb 预览功能标志的形式添加,并自版本 3.12.0 起普遍可用。
复合类型目前仅在 MongoDB 上可用。
复合类型(在 MongoDB 中称为嵌入式文档)通过允许您定义新的对象类型来支持将记录嵌入到其他记录中。复合类型的结构和类型与模型类似。
要定义复合类型,请使用 type 块。例如,以下 schema
model Product {
id String @id @default(auto()) @map("_id") @db.ObjectId
name String
photos Photo[]
}
type Photo {
height Int
width Int
url String
}
在这种情况下,Product 模型有一个存储在 photos 中的 Photo 复合类型列表。
使用复合类型时的注意事项
复合类型只支持有限的属性集。支持以下属性
@default@map- 原生类型,例如
@db.ObjectId
复合类型中不支持以下属性
@unique@id@relation@ignore@updatedAt
但是,仍然可以通过在使用复合类型的模型级别上使用 @@unique 属性来定义唯一约束。有关更多详细信息,请参阅复合类型唯一约束。
可以通过在使用复合类型的模型级别上使用 @@index 属性来定义索引。有关更多详细信息,请参阅复合类型索引。
使用函数
Prisma schema 支持许多函数。这些函数可用于指定模型字段的默认值。
例如,createdAt 的默认值为 now()
- 关系型数据库
- MongoDB
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
}
model Post {
id String @default(auto()) @map("_id") @db.ObjectId
createdAt DateTime @default(now())
}
cuid() 和 uuid() 由 Prisma ORM 实现,因此在底层数据库 schema 中不可“见”。您仍然可以在使用内省时使用它们,方法是手动更改 Prisma schema 并生成 Prisma Client,在这种情况下,值将由 Prisma Client 的查询引擎生成
对 autoincrement()、now() 和 dbgenerated(...) 的支持因数据库而异。
关系数据库连接器在数据库级别实现 autoincrement()、dbgenerated(...) 和 now()。MongoDB 连接器不支持 autoincrement() 或 dbgenerated(...),并且 now() 在 Prisma ORM 级别实现。auto() 函数用于生成 ObjectId。
关系
有关更多示例以及模型之间关系的信息,请参阅关系文档。
Prisma Client 中的模型
查询(CRUD)
数据模型定义中的每个模型都会在生成的 Prisma Client API 中生成许多 CRUD 查询
findMany()findFirst()findFirstOrThrow()findUnique()findUniqueOrThrow()create()update()upsert()delete()createMany()createManyAndReturn()updateMany()updateManyAndReturn()deleteMany()
这些操作可通过 Prisma Client 实例上生成的属性进行访问。默认情况下,属性的名称是模型名称的小写形式,例如 User 模型的 user 或 Post 模型的 post。
这是一个说明 Prisma Client API 中 user 属性用法的示例
const newUser = await prisma.user.create({
data: {
name: 'Alice',
},
})
const allUsers = await prisma.user.findMany()
类型定义
Prisma Client 还生成反映模型结构的类型定义。这些是生成的 @prisma/client node 模块的一部分。
使用 TypeScript 时,这些类型定义确保所有数据库查询都是完全类型安全的,并在编译时进行验证(即使是使用 select 或 include 的部分查询)。
即使使用纯 JavaScript,类型定义也包含在 @prisma/client node 模块中,从而在您的编辑器中启用 IntelliSense/自动完成等功能。
注意:实际类型存储在
.prisma/client文件夹中。@prisma/client/index.d.ts导出此文件夹的内容。
例如,上面 User 模型的类型定义如下所示
export type User = {
id: number
email: string
name: string | null
role: string
}
请注意,关系字段 posts 和 profile 默认不包含在类型定义中。但是,如果您需要 User 类型的变体,您仍然可以使用 Prisma Client 生成的一些辅助类型来定义它们(在这种情况下,这些辅助类型将被称为 UserGetIncludePayload 和 UserGetSelectPayload)。
限制
记录必须唯一标识
Prisma ORM 目前只支持至少有一个唯一字段或字段组合的模型。实际上,这意味着每个 Prisma 模型必须至少具有以下属性之一
@id或@@id用于单字段或多字段主键约束(每个模型最多一个)@unique或@@unique用于单字段或多字段唯一约束