关于程序员:面向Nodejs和TypeScript的下一代ORM工具Prisma

3次阅读

共计 15044 个字符,预计需要花费 38 分钟才能阅读完成。

面向 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.jsTypeScript主动生成和类型平安的查问生成器
  • 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 无需批改,其依据不同的数据库还反对 mysqlsqlitesqlservermongodb

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
} 

其反映的的数据库如下所示:

模型会映射到数据源的底层构造

  • PostgreSQLMySQL 等关系型数据库中,model 映射至 
  • MongoDB 中,model 映射至 汇合

**model  反对的全副字段标量类型能够参考文档, 值得注意的是,下面 User 中的 postsprofile是关系字段,别离代表一个用户有多个 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

对应内容如下

-- CreateTable
CREATE TABLE "User" (
    "id" SERIAL NOT NULL,
    "name" TEXT NOT NULL,

    CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE 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")
);

-- AddForeignKey
ALTER 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
-- AlterTable
ALTER 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 命令:

  1. 查看数据库,以推断和执行所需的更改,使数据库架构反映 Prisma 架构的状态。
  2. 默认状况下,将更改利用到数据库架构后会触发生成器 (例如,Prisma Client)。您不须要手动调用Prisma 生成
  3. 如果 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 文件夹下

  1. 装置 @prisma/clientnpm 包:

    npm install @prisma/client
  2. 应用以下命令生成 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 type
interface CustomNodeJsGlobal extends NodeJS.Global {prisma: PrismaClient}

// Prevent multiple instances of Prisma Client in development
declare const global: CustomNodeJsGlobal

const prisma = global.prisma || new PrismaClient()

if (process.env.NODE_ENV === 'development') global.prisma = prisma

export 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',},
})

// 按 ID
const 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 个赞的 最新创立的用户

  1. 按升序 ID 排序用户(最大的优先)- 最大的 ID 是最近的 ID
  2. 以升序返回第一个用户,其中至多有一个帖子有 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 字段:

// 返回一个对象或 null
const 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 或其余迁徙工具的我的项目的典型工作流如下:

  1. 更改数据库架构 (例如应用纯 SQL)
  2. 运行 prisma db pull 更新 Prisma 架构
  3. 运行 prisma generate Prisma Client
  4. 在应用程序中应用更新的 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 框架,它能够连贯到多种数据库类型(如 PostgreSQLMySQLSQLiteSQL 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 有什么区别和劣势?

    尽管 PrismaTypeORM解决了相似的问题,但它们的工作形式十分不同。

    TypeORM是一种传统的 ORM,将表映射到模型类。这些模型类可用于生成 SQL 迁徙。而后,模型类的实例在运行时为应用程序提供CRUD 查问接口。

    Prisma是一种新类型的 ORM,能够缓解传统ORM 中许多问题,例如臃肿的模型实例、业务逻辑与存储逻辑混合、不足类型安全性或由懒加载引起的不可预测查问等。

    TypeORM为其查找办法(例如 findfindByIdsfindOne 等)提供了一个 select 选项,例如:

    const postRepository = getManager().getRepository(Post)
    const publishedPosts: Post[] = await postRepository.find({where: { published: true},
        select: ['id', 'title'],
    })

    尽管返回的 publishedPosts 数组中的每个对象在运行时只携带所选的 idtitle属性,但 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 多平台公布

正文完
 0