面向Node.js和TypeScript的下一代ORM工具Prisma
筹备
数据库筹备
数据库能够通过docker
跑一个服务,然而目前市场上也有好几个能提供收费的PostgreSQL
服务云厂商,有如下几个
Supabase
Heroku
Railway
Supabase
是一款开源的后端即服务(Backend-as-a-Service
)平台,它提供了相似于Firebase
的性能,包含实时数据同步、身份验证和受权,以及通过SQL
查问API
拜访PostgreSQL
数据库。Supabase
收费打算能够创立两个利用,并且PostgreSQL
数据库每个月提供1GB
的存储空间和50GB
的传输量,集体开发应该入不敷出,这里我采纳Supabase
,首先注册个账号,新建个利用
创立利用后,在设置选项中查看连贯选项, 能够看到在这个数据库URI
地址
Supabase
自身就提供了数据库相干操作的性能,能够间接通过快捷的UI
交互,创建表格和字段,执行查问语句,查看表数据等,但这里咱们重点是应用它来学习 Prisma
这一新一代ORM
工具
初始化我的项目
Prisma
次要由三局部组成:
- Prisma Client: 为
Node.js
和TypeScript
主动生成和类型平安的查问生成器 - Prisma Migrate: 迁徙工具,能够轻松地将数据库模式从原型设计利用到生产
- Prisma Studio: 用于查看和编辑数据库中数据的
GUI
可用于各种工具和框架, 以Nextjs
应用举例,你能够决定在构建时(getStaticProps
)、申请时(getServerSideProps
)、应用 API
路由或将后端齐全拆散成独立的服务器来拜访您的数据库,如下别离对应四种场景
首先通过命令创立一个Nextjs
我的项目
npx create-next-app@latest
装置Prisma
npm install prisma
初始化prisma
设置
npx prisma init
执行完后,多了个配置文件prisma/schema.prisma
和.env
文件,内容如下
generator client { provider = "prisma-client-js"}datasource db { provider = "postgresql" url = env("DATABASE_URL")}
其中datasource代表数据源
provider
默认就是postgresql
无需批改,其依据不同的数据库还反对mysql
、sqlite
、sqlserver
、mongodb
等
url
字段指连贯 URL
。通常由以下局部组成(SQLite
除外):
User
: 数据库用户名Password
: 数据库用户明码Host
: 数据库服务器的 ip 或者域名Port
: 数据库服务器的端口Database name
: 数据库名称
DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
依据提醒,咱们将env
中的数据库地址批改成咱们的地址
Prisma Schema
Prisma schema 的数据模型定义局部定义了你的利用模型(也称为 Prisma 模型)。模型:
- 形成了应用领域的 实体
- 映射到数据库的 表(关系型数据库,例如 PostgreSQL)或 汇合 (MongoDB)
- 形成 Prisma Client API 中 查问 的根底
假如咱们有以下模型
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}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])}model Category { id Int @id @default(autoincrement()) name String posts Post[] @relation(references: [id])}enum Role { USER ADMIN}
其反映的的数据库如下所示:
模型会映射到数据源的底层构造
- 在
PostgreSQL
和MySQL
等关系型数据库中,model
映射至 表 MongoDB
中,model
映射至 汇合
**model
反对的全副字段标量类型能够参考文档, 值得注意的是,下面User
中的posts
和profile
是关系字段,别离代表一个用户有多个posts
和一个用户有一个关联的profile
, 这另个字段属于关系字段,关系字段在 Prisma
层定义模型间的分割,且 不存在于数据库中。这些字段用于生成 Prisma Client
, 如果没有这个关系字段,Prisma插件会有正告
这时候能够通过执行以下命令来主动补全
npx prisma format
Prisma Migrate
Prisma Migrate
是一个命令式数据库架构迁徙工具,它使您可能:
- 放弃数据库架构与Prisma 架构的同步
- 保护数据库中的现有数据
Prisma Migrate
会生成一个.sql
迁徙文件的历史记录,能在开发或和部署中发挥作用。
<aside>
不反对 MongoDB
Prisma Migrate 目前不反对 MongoDB connector
</aside>
数据模型中的每项性能都会映射成根底数据库中的相应性能,创立Prisma
模型
model User { id Int @id @default(autoincrement()) name String Post Post[]}model Post { id Int @id @default(autoincrement()) title String published Boolean @default(true) authorId Int author User @relation(fields: [authorId], references: [id])}
创立第一个迁徙:
npx prisma migrate dev --name init
执行完后目录下多了一个文件
migrations/ └─ 20230420131352_init/ └─ migration.sql
对应内容如下
-- CreateTableCREATE TABLE "User" ( "id" SERIAL NOT NULL, "name" TEXT NOT NULL, CONSTRAINT "User_pkey" PRIMARY KEY ("id"));-- CreateTableCREATE TABLE "Post" ( "id" SERIAL NOT NULL, "title" TEXT NOT NULL, "published" BOOLEAN NOT NULL DEFAULT true, "authorId" INTEGER NOT NULL, CONSTRAINT "Post_pkey" PRIMARY KEY ("id"));-- AddForeignKeyALTER TABLE "Post" ADD CONSTRAINT "Post_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
同时咱们的数据库的表也被创立进去
如果咱们再次新增一个性别字段gender
model User { id Int @id @default(autoincrement()) gender Int name String posts Post[]}
创立第二次迁徙
npx prisma migrate dev --name add_gender
Prisma
架构再次与数据库架构同步,迁徙历史记录里蕴含了两次迁徙
migrations/ └─ 20230420131352_init/ └─ migration.sql └─ 20230420132624_add_gender/ └─ migration.sql
-- AlterTableALTER TABLE "User" ADD COLUMN "gender" INTEGER NOT NULL;
db push
[db push](https://prisma.yoga/reference/api-reference/command-reference/#db-push)
应用与 Prisma Migrate
相干的引擎来同步 Prisma
架构和数据库架构,最适宜于架构原型。db push
命令:
- 查看数据库,以推断和执行所需的更改,使数据库架构反映
Prisma
架构的状态。 - 默认状况下,将更改利用到数据库架构后会触发生成器 (例如,
Prisma Client
)。您不须要手动调用Prisma生成
。 如果
db push
预测到更改可能导致数据失落,它会:- 抛出一个谬误
- 如果仍要进行更改,则须要加上
-accept-data-loss
选项
<aside>
请留神: db push
不与迁徙交互或依赖迁徙。不会更新迁徙表,也不会生成迁徙文件。
</aside>
在开发中,咱们可能也不确定须要哪些字段,字段哪个类型适合,因而会频繁批改数据库构造,会继续迭代 schema
,当迭代到满足需要直到它达到一个绝对稳固的状态时,这时咱们才生成一个迁徙文件,达到初始原型的步骤没有被保留也不须要保留, 该命令罕用于数据库原型设计阶段。
退出咱们在User
中再增加一个头像avatar
字段,并执行
npx prisma db push
这是近程数据库表构造曾经更新,再次生成迁徙记录时
npx prisma migrate dev --name added-avatar
会打印正告提醒
因为您在原型设计期间手动进行的更改和应用 db push
进行的更改不属于迁徙历史记录, 会检测到已有的迁徙和数据库目前状态对应不起来。Prisma Migrate
会复制现有的迁徙历史,依据 schema
变动生成一个新的迁徙,并将这些变动利用到数据库。
Prisma Studio
Prisma Studio
是数据库中数据的可视化编辑器
npx prisma studio
执行下面命令会关上http://localhost:5555页面
在页面能够查看我的项目的所有 model
并用一种很不便的交互方式来操作数据库
Prisma Client
Prisma Client
是一个主动生成的类型平安查问结构器,可依据你的数据进行定制。
生成 **PrismaClient
实例
Prisma Client
是一个跟据你的数据库 schema
主动生成的定制化数据库客户端 client
。默认状况下, Prisma Client
被生成到 node_modules/.prisma/client
文件夹下
装置
@prisma/client
npm 包:npm install @prisma/client
应用以下命令生成 Prisma Client:
prisma generate
<aside>
重要提醒
每次对 Prisma schema
进行更改后,你都须要从新运行命令 prisma generate
去更新生成的 Prisma Client
代码。
</aside>
例如咱们的schema
从
model User { id Int @id @default(autoincrement()) Post Post[]}
批改为
model User { id Int @id @default(autoincrement()) posts Post[]}
再次运行prisma generate
命令后, 类型也失去更新,提醒须要进行批改
**创立 PrismaClient
实例
以下示例演示了如何应用 默认输入门路 导入并创立你 生成的 PrismaClient 实例:
import { PrismaClient } from '@prisma/client'const prisma = new PrismaClient()
你的应用程序通常只该当创立 一个PrismaClient
实例。如何实现这一点取决于你是在 长期运行的应用程序 还是在 无主机 (serverless) 环境中应用 Prisma
。这样做的起因是每个 PrismaClient
实例会保护一个连接池,意味着大量数据库连贯会 耗尽数据库连接数限度, 太多的数据库连贯可能会 使你的数据库变慢并最终导致谬误,这实用于所有数据库连接器 。
在长期运行的应用程序中的PrismaClient
在长期运行的应用程序中,倡议:
✔ 创立一个的
PrismaClient
实例,并在整个应用程序中重复使用它默认状况下实用默认的池大小(
num_physical_cpus * 2 + 1
)- 你不须要设置connection_limit
参数- ✔ 将
PrismaClient
调配给一个全局变量仅在开发环境中以避免因创立新实例而产生热重载
该对象在模块第一次被导入时被缓存。随后的申请会返回缓存的对象,而不是创立一个新的PrismaClient
:
import { PrismaClient } from '@prisma/client'let prisma = new PrismaClient()export default prisma
避免热重载创立PrismaClient
的新实例
像Next.js这样的框架反对热重载扭转的文件,这使你可能在不重启的状况下看到你的应用程序的变动。然而,如果框架刷新了负责导出PrismaClient
的模块,这可能会导致开发环境中呈现额定的、不须要的PrismaClient
实例。
作为一个变通方法,你能够在开发环境中把PrismaClient
作为一个全局变量来存储,因为全局变量不会被从新加载:
import { PrismaClient } from '@prisma/client'// add prisma to the NodeJS global typeinterface CustomNodeJsGlobal extends NodeJS.Global { prisma: PrismaClient}// Prevent multiple instances of Prisma Client in developmentdeclare const global: CustomNodeJsGlobalconst prisma = global.prisma || new PrismaClient()if (process.env.NODE_ENV === 'development') global.prisma = prismaexport default prisma
连贯和断开
PrismaClient
应用以下两种办法连贯和断开数据源:
[$connect()](https://prisma.yoga/reference/api-reference/prisma-client-reference/#connect-1)
[$disconnect()](https://prisma.yoga/reference/api-reference/prisma-client-reference/#disconnect-1)
在大多数状况下,你 不须要显式调用这些办法。PrismaClient
会在你运行第一条查问时主动连贯数据库,并创立一个 连接池,而后在 Node.js
过程完结时断开连接。
CRUD 增删改查
接下来介绍如何应用生成的 Prisma Client API 执行 CRUD 操作
所有示例均基于以下 schema:
开展示例 schema
model ExtendedProfile { id Int @id @default(autoincrement()) biography String user User @relation(fields: [userId], references: [id]) userId Int}model User { id Int @id @default(autoincrement()) name String? email String @unique profileViews Int @default(0) role Role @default(USER) coinflips Boolean[] posts Post[] profile ExtendedProfile?}model Post { id Int @id @default(autoincrement()) title String published Boolean @default(true) author User @relation(fields: [authorId], references: [id]) authorId Int comments Json? views Int @default(0) likes Int @default(0) categories Category[]}model Category { id Int @id @default(autoincrement()) name String @unique posts Post[]}enum Role { USER ADMIN}
创立
创立单个
以下查问创立([create](https://prisma.yoga/reference/api-reference/prisma-client-reference/#create)
)具备两个字段的单个用户:
const user = await prisma.user.create({ data: { email: 'elsa@prisma.io', name: 'Elsa Prisma', },})
创立多个记录
Prisma Client 在 2.20.0 和更高版本中反对将大量插入作为 根底可用 性能。
以下 [createMany](https://prisma.yoga/reference/api-reference/prisma-client-reference/#createmany)
查问创立多个用户并跳过任何反复项 (email
必须是惟一的):
const createMany = await prisma.user.createMany({ data: [ { name: 'Bob', email: 'bob@prisma.io' }, { name: 'Bobo', email: 'bob@prisma.io' }, // 惟一键反复! { name: 'Yewande', email: 'yewande@prisma.io' }, { name: 'Angelique', email: 'angelique@prisma.io' }, ], skipDuplicates: true, // 跳过 'Bobo'})
读取
按 ID 或惟一标识符获取记录
以下查问按惟一标识符或 ID 返回单个记录 ([findUnique](https://prisma.yoga/reference/api-reference/prisma-client-reference/#findunique)
)
// 按惟一标识符const user = await prisma.user.findUnique({ where: { email: 'elsa@prisma.io', },})// 按 IDconst user = await prisma.user.findUnique({ where: { id: 99, },})
获取所有记录
以下 [findMany](https://prisma.yoga/reference/api-reference/prisma-client-reference/#findmany)
查问返回 所有 User
记录:
const users = await prisma.user.findMany()
你也能够 对你的后果进行分页。
获取与特定条件匹配的第一条记录
以下 [findFirst](https://prisma.yoga/reference/api-reference/prisma-client-reference/#findfirst)
查问返回 至多有一个帖子有超过 100 个赞的 最新创立的用户:
- 按升序 ID 排序用户(最大的优先)- 最大的 ID 是最近的 ID
- 以升序返回第一个用户,其中至多有一个帖子有 100 个以上的赞
const findUser = await prisma.user.findFirst({ where: { posts: { some: { likes: { gt: 100 } } } }, orderBy: { id: "asc" } })}
获取通过过滤的记录列表
Prisma Client
反对记录字段和相干记录字段的 过滤。
按单个字段值过滤
上面的查问返回所有 User
记录,其中蕴含以 "prisma.io"
结尾的电子邮件:
const users = await prisma.user.findMany({ where: { email: { endsWith: "prisma.io" } }, }
按多个字段值过滤
以下查问应用 operators 组合返回名称以 E
结尾的用户 或 至多具备 1 个 profile 的管理员:
const users = await prisma.user.findMany({ where: { OR: [ { name: { startsWith: 'E', }, }, { AND: { profileViews: { gt: 0, }, role: { equals: 'ADMIN', }, }, }, ], },})
按相干记录字段值过滤
以下查问返回的用户电子邮件以 prisma.io
结尾,并且 至多有 一 篇(some
)为未公布的帖子:
const users = await prisma.user.findMany({ where: { email: { endsWith: "prisma.io" }, posts: { some: { published: false } } }, }
无关过滤相干字段值的更多示例,请参见 应用关系。
抉择字段
默认状况下,当查问返回记录(与计数相同)时,后果包含 默认抉择集:
- Prisma schema 中定义的 所有 标量字段(包含枚举)
- 无 关系
要自定义后果,请执行以下操作:
- 应用
[select](https://prisma.yoga/reference/api-reference/prisma-client-reference/#select)
来返回特定字段 - 你还能够应用嵌套的select
来蕴含关系字段 - 应用
[include](https://prisma.yoga/reference/api-reference/prisma-client-reference/#include)
来明确 包含关系
能够仅抉择所需的字段和关系,而不依赖默认抉择集 ✔ 减小响应的大小并 ✔ 进步查问速度。
以下示例仅返回 email
和 name
字段:
抉择特定字段
应用 select
返回无限的字段子集,而不是所有字段。以下示例仅返回 email
和 name
字段:
// 返回一个对象或 nullconst getUser: object | null = await prisma.user.findUnique({ where: { id: 22, }, select: { email: true, name: true, },})
包含关系并抉择关系字段
要返回 特定关系字段,你能够:
- 应用嵌套的
select
-在include
中应用select
要返回 all 关系字段,请仅应用 include - 例如 { include: { posts: true } }。
以下查问应用嵌套的 select
来抉择每个用户的 name
和每个相干帖子的 title
:
const users = await prisma.user.findMany({ select: { name: true, posts: { select: { title: true, }, }, },})
Show CLI results
以下查问在 include
中应用 select
,并返回 所有 用户字段和每篇文章的 title
字段:
const users = await prisma.user.findMany({ // 返回所有用户字段 include: { posts: { select: { title: true, }, }, },})
Show CLI results
无关查问关系的更多信息,请参阅以下文档:
- 蕴含关系 (蕴含所有字段)
- 抉择特定关系字段
分页
Prisma Client 反对偏移分页和基于游标的分页。
偏移分页
偏移分页应用 skip
和 take
跳过肯定数量的后果并抉择无限的范畴。以下查问跳过前 3 个 Post
记录并返回记录 4 - 7:
const results = await prisma.post.findMany({ skip: 3, take: 4,})
要实现后果页面,只需 skip
页面数乘以每页显示的后果数即可。
基于游标的分页
基于游标的分页应用 cursor
and take
在给定 游标 之前或之后返回一组无限的后果。游标在后果集中为你的地位增加书签,并且必须是惟一的间断列,例如 ID 或工夫戳。
以下示例返回蕴含单词 "Prisma"
的前 4 条 Post
记录,并将最初一条记录的 ID 保留为 myCursor
:
留神:因为这是第一个查问,因而没有要传递游标。
const firstQueryResults = prisma.post.findMany({ take: 4, where: { title: { contains: 'Prisma'/* 可选过滤器 */, }, }, orderBy: { id: 'asc', },})// 在后果集中为你的地位增加书签 - 在此// 案例,列表 4 中最初一篇文章的 ID。const lastPostInResults = firstQueryResults[3]// 记住:从零开始的索引!:)const myCursor = lastPostInResults.id// 示例: 29
下图显示了前 4 个后果 - 或第 1 页的 ID。下一个查问的游标为 29:
第二个查问返回前 4 个 Post
记录,这些记录蕴含单词 "Prisma"
在提供的游标之后(换句话说,大于 29 的 ID):
const secondQueryResults = prisma.post.findMany({ take: 4, skip: 1,// 跳过游标 cursor: { id: myCursor, }, where: { title: { contains: 'Prisma'/* 可选过滤器 */, }, }, orderBy: { id: 'asc', },})const lastPostInResults = secondQueryResults[3]// 记住:从零开始的索引!:)const myCursor = lastPostInResults.id// 示例: 52
下图显示了 ID 为 29 的记录 之后 的前 4 条 Post
记录。在本例中,新游标为 52:
嵌套写入
嵌套写入 容许你应用多个 操作 执行单个 Prisma Client API
调用,这些操作波及多个 相干的 记录。例如,创立 用户 和 post
或更新 订单 和 发票。Prisma Client
确保所有操作作为一个整体胜利或失败。
上面的示例演示了带有 create
的嵌套写入:
// 在一个事务中创立一个具备两个帖子的新用户const newUser: User = await prisma.user.create({ data: { email: 'alice@prisma.io', posts: { create: [ { title: 'Join the Prisma Slack on https://slack.prisma.io' }, { title: 'Follow @prisma on Twitter' }, ], }, },})
以下示例演示了带有 update
的嵌套写入:
// 在单个事务中更改帖子的作者const updatedPost: Post = await prisma.post.update({ where: { id: 42 }, data: { author: { connect: { email: 'alice@prisma.io' }, }, },})
内省
当将 Prisma 增加到现有我的项目时,内省通常用于生成数据模型的 初始 版本。
内省能做什么?
内省有一个次要性能: 反映以后数据库架构的数据模型来填充您的 Prisma 架构。
以下是它的次要性能概述:
- 将数据库中的 表 映射到Prisma models
- 将数据库中的 列 映射到 Prisma 模型的字段
- 将数据库中的 indexes 映射到 Prisma 架构中的indexes
- 将 database constraints 映射到 Prisma 架构中的attributes或type modifiers
prisma db pull
命令
您能够应用 Prisma CLI 的 prisma db pull
命令内省您的数据库。请留神,应用此命令须要在您的 Prisma 架构 datource
中设置连贯 URL。
内省的工作流
不应用 Prisma Migrate
,而是应用纯 SQL
或其余迁徙工具的我的项目的典型工作流如下:
- 更改数据库架构 (例如应用纯
SQL
) - 运行
prisma db pull
更新Prisma
架构 - 运行
prisma generate
Prisma Client
- 在应用程序中应用更新的
Prisma Client
请留神,随着应用程序的倒退,此过程能够反复有限次。
咱们能够执行以下命令来生成您的 Prisma
模型:
npx prisma db pull
创立了以下 Prisma 模式:
model category { id Int @id @default(autoincrement()) name String post_categories_category post_categories_category[]}model profile { id Int @id @default(autoincrement()) bio String? userId Int? @unique user user? @relation(fields: [userId], references: [id])}model user { id Int @id @default(autoincrement()) name String? email String @unique post post[] profile profile?}
调整 Prisma schema
(可选)
所有调整都是可选的,不想调整任何内容,能够跳到下一步。 后续随时返回调整。
Prisma
的命名与以后 snake_case
的命名约定不同:
- 模型(
Prisma model
)命名恪守PascalCase
- 字段(
field
)命名恪守camelCase
能够应用 @@map
和 @map
映射的模型和字段名称到已有的数据表和列名来调整命名。
另请留神,能够重命名 关联字段 以优化稍后将用于向数据库发送查问的 Prisma Client API
。 例如,user
模型上的 post
字段是数组格局,因而这个字段的更好名称是 posts
以表明它是复数模式。
model Category { id Int @id @default(autoincrement()) name String postsToCategories PostToCategories[] @@map("category")}model Profile { id Int @id @default(autoincrement()) bio String? userId Int? @unique user User? @relation(fields: [userId], references: [id]) @@map("profile")}model User { id Int @id @default(autoincrement()) name String? email String @unique posts Post[] profile Profile? @@map("user")}
总结
最初咱们以问答的模式来总结一下prisma
Prisma
是什么?它的作用是什么?Prisma
是一款现代化的ORM框架,它能够连贯到多种数据库类型(如PostgreSQL
、MySQL
、SQLite
和SQL Server
),提供高效、类型平安和易于应用的API
,从而不便地操作和治理数据库。它的作用是帮忙开发人员疾速构建可扩大、高性能的数据库应用程序,同时缩小手写底层SQL
代码的工作量。Prisma
有哪些次要的个性和性能?Prisma的次要个性和性能包含:
- 数据建模:反对通过编写数据模型(
schema
)定义应用程序的数据结构来定义数据库中的表、字段、关系、索引等内容。 - 数据查问:提供基于类型平安的查问
API
来查询数据库,并反对AND/OR
逻辑运算、分页、过滤、排序、连贯查问等高级性能。 - 数据批改:反对通过数据编辑
API
来增加、更新和删除数据库中的数据,并提供事务管理等性能。 - 数据迁徙:反对数据库模式的迁徙操作,不便在开发、测试和生产环境之间进行数据库的版本控制和治理。
- 数据建模:反对通过编写数据模型(
Prisma
如何解决关系型数据?Prisma
的关系型数据库反对包含一对一、一对多和多对多关系。Prisma
的数据建模语言容许开发人员定义表之间的关系,并在查问时主动解决关系查问、连贯和过滤。Prisma
基于外键关系主动治理关系的连贯和解除连贯。在定义数据模型时,能够应用关系属性来建设连贯。例如,上面的代码定义了一个名为posts
的文档汇合:model Post { id Int @id @default(autoincrement()) title String body String comments Comment[]}model Comment { id Int @id @default(autoincrement()) body String postId Int post Post @relation(fields: [postId], references: [id])}
在这个例子中,
Comment
模型具备一个指向Post
模型的援用,并且在执行查问时,Prisma
会主动解决两个模型之间的连贯。Prisma
与传统TypeORM
有什么区别和劣势?尽管
Prisma
和TypeORM
解决了相似的问题,但它们的工作形式十分不同。TypeORM
是一种传统的ORM
,将表映射到模型类。这些模型类可用于生成SQL迁徙。而后,模型类的实例在运行时为应用程序提供CRUD
查问接口。Prisma
是一种新类型的ORM
,能够缓解传统ORM
中许多问题,例如臃肿的模型实例、业务逻辑与存储逻辑混合、不足类型安全性或由懒加载引起的不可预测查问等。TypeORM
为其查找办法(例如find
、findByIds
、findOne
等)提供了一个select
选项,例如:const postRepository = getManager().getRepository(Post)const publishedPosts: Post[] = await postRepository.find({ where: { published: true }, select: ['id', 'title'],})
尽管返回的
publishedPosts
数组中的每个对象在运行时只携带所选的id
和title
属性,但TypeScript
编译器并不知道这一点。它将容许您在查问之后拜访Post
实体上定义的任何其余属性,例如:const post = publishedPosts[0]// TypeScript编译器没有问题if (post.content.length > 0) { console.log(`This post has some content.`)}
此代码将导致运行时谬误:
TypeError: Cannot read property 'length' of undefined
Prisma Client
能够在雷同状况下保障齐全类型平安,并避免您拜访未从数据库检索到的字段。思考应用Prisma Client
查问雷同示例,在这种状况下,TypeScript
编译器将在编译时抛出以下谬误:[ERROR] 14:03:39 ⨯ Unable to compile TypeScript:src/index.ts:36:12 - error TS2339: Property 'content' does not exist on type '{ id: number; title: string; }'.42 if (post.content.length > 0) {
这是因为
Prisma Client
动静生成其查问的返回类型。在本例中,publishedPosts
的类型如下所示:const publishedPosts: { id: number title: string}[]
因而,您无法访问未有类型申明的属性
本文由mdnice多平台公布