Featured image of post Prisma 知识点归纳(一)数据模型与关系 2023

Prisma 知识点归纳(一)数据模型与关系 2023

本文含有: Prisma 简单查询, 数据模型的定义, 字段修饰符, 属性函数, 枚举, 一对一, 一对多, 多对多关系的定义

该文档的基础是建立在学过关系型数据库的基础上,并且以下内容是根据 API 文档进行参考编写的(没办法,概念那太零散了)。

https://prisma.yoga/getting-started

常用命令

  • 先介绍几个命令
# 1) 现有库
pnpm i prisma --save-dev
pnpm i @prisma/client

# 2) 新库
mkdir hello-prisma
cd hello-prisma
pnpm init -y
pnpm install prisma typescript ts-node @types/node --save-dev
pnpm i @prisma/client

# 创建项目
npx prisma init

# 拉取数据库模型
npx prisma db pull

# 生成你的Prisma Client库
# 作用: 在 pull 模型后生成连接库
npx prisma generate

# 模型映射到数据库架构
# 用法: 修改完数据模型后 映射到 数据库架构
npx prisma migrate dev --name init
  • tsconfig.json
{
  "compilerOptions": {
    "sourceMap": true,
    "outDir": "dist",
    "strict": true,
    "lib": ["esnext"],
    "esModuleInterop": true
  }
}
  • .env
    • USER: 数据库用户的名称
    • PASSWORD: 数据库用户的密码
    • PORT: 数据库服务器运行的端口(关系型数据库通常是3306)
    • DATABASE: 数据库名称
DATABASE_URL="MYSQL://USER:PASSWORD@HOST:PORT/DATABASE"
  • prisma/schema.prisma
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "关系型数据库"
  url      = env("DATABASE_URL")
}

简单的查询

查询 user 表的所有数据

import { PrismaClient } from "@prisma/client";

const prisma = new PrismaClient();

async function main() {
  const allUsers = await prisma.user.findMany();
  console.log(allUsers);
}

main()
  .catch((e) => {
    throw e;
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
npx ts-node index.ts

数据模型

每个 Model 必须至少定义以下一个属性:

  • @unique
  • ``@@unique`
  • @id
  • @@id

字段类型这里不会讲,请自行看文档。

字段修饰符

该内容建议直接看 关系 章节。

  • ?:可选(零个或一个)
    • Profile?:一个用户对应 零或一个配置文件
  • []:零个或多个
    • Post[]:一个用户可以有多篇文章
model User {
  id   Int     @id @default(autoincrement())
  name String?
}

model User {
  id             Int      @id @default(autoincrement())
  posts          Post[]
  favoriteColors String[]
}

MongoDB

  • 不同点
  • 标量列表需要 @db.Array(String),其中参数与标量类型匹配(例如,String[]
model User {
  id             String   @id @default(dbgenerated()) @map("_id") @db.ObjectId
  posts          Post[]
  favoriteColors String[] @db.Array(String)
}

属性

关系型数据库

  • 1、ID
    • 单字段:@id
    • 复合字段:@@id([])
    • MongoDB 不支持 @@id
  • 2、默认值
    • @default
  • 3、唯一值
    • 单字段:@unique
    • 复合字段:@@unique([])
  • 4、索引
    • @@index([title, content])
  • 5、定义关系(请看关系 一对多 章节)
    • @relation
    • 对应数据库类型: FOREIGN KEY / REFERENCES
      • @relation 属性上的 name 参数的名称可以省略(references是必需的)
  • 6、映射
    • @@map()
      • Post 模型映射至数据库 Posts 表。
  • 7、获取更新时间
    • @updatedAt
-- 关系型数据库
model Post {
  id        Int      @id @default(autoincrement())
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  title     String   @db.VarChar(255)
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int

  @@unique([authorId, title])
  @@index([title, content])
  @@map("Posts")
}

model User {
  firstName String
  lastName  String
  email     String @unique
  posts Post[]

  @@id([firstName, lastName])
}

MongoDB

  • 只讲和 关系型数据库 的不同点。
  • 1、ID
    • 使用 String 或者 Bytes 字段类型
    • 使用 @db.ObjectId 对字段修饰
    • (可选),使用 @default() 值对字段进行注释,该值使用 dbgenerated()函数 自动生成 ObjectId
  • 2、索引
    • 不支持
-- MondoDB
model Post {
  id         String     @id @default(dbgenerated()) @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])
}

model User {
  id String @id @default(dbgenerated()) @map("_id") @db.ObjectId
  id String @db.ObjectId @map("_id") @default(dbgenerated())
}

属性函数

  • autoincrement():自增
    • 不支持 MondoDB
  • cuid():唯一标识符
    • String 类型兼容
  • uuid()
    • String 类型兼容
  • now():当前时间戳
-- 关系型数据库
model User {
  id   String @id @default(autoincrement())
  id   String @id @default(cuid())
  id   String @id @default(uuid())
  createdAt DateTime @default(now())
}

-- mongoDB
model User {
  id   String @id @default(cuid()) @map("_id")
  id   String @id @default(uuid()) @map("_id")
  createdAt DateTime @default(now())
}

枚举

model User {
  id    Int     @id @default(autoincrement())
  email String  @unique
  name  String?
  role  Role    @default(USER)
}

enum Role {
  USER
  ADMIN
}

关系

一对一

  • 指两侧最多可以关联 一条 记录的关系。
  • 例如下面例子
    • 一个 User 可以有零或一个 Profile
    • 但是一个 Profile 必须要关联一个 User
model User {
  id      Int      @id @default(autoincrement())
  profile Profile?
}

model Profile {
  id     Int  @id @default(autoincrement())
  user   User @relation(fields: [userId], references: [id])
  userId Int // 关系标量字段 (在上述 `@relation` 属性中使用)
}

对应以下 SQL

CREATE TABLE "User" (
    id SERIAL PRIMARY KEY
);
CREATE TABLE "Profile" (
    id SERIAL PRIMARY KEY,
    "userId" INTEGER NOT NULL UNIQUE,
    FOREIGN KEY ("userId") REFERENCES "User"(id)
);
  • 同时可以在另一侧存储关系外键
model User {
  id        Int      @id @default(autoincrement())
  profile   Profile? @relation(fields: [profileId], references: [id])
  profileId Int? // 关系标量字段 (在上述 `@relation` 属性中使用)
}

model Profile {
  id   Int   @id @default(autoincrement())
  user User?
}
  • 多字段关系——仅限关系数据库
model User {
  firstName String
  lastName  String
  profile   Profile?

  @@id([firstName, lastName])
}

model Profile {
  id            Int    @id @default(autoincrement())
  user          User   @relation(fields: [userFirstName, userLastName], references: [firstName, lastName])
  userFirstName String // 关系标量字段 (在上述 `@relation` 属性中使用)
  userLastName  String // 关系标量字段 (在上述 `@relation` 属性中使用)
}

一对多

  • 一个 User 可以有零或多个 Post(注意,这里是多个,上面一对一是 一个
  • 但是一个 Post 必须要关联一个 User
    • 注意!这是 Post[]
model User {
  id    Int    @id @default(autoincrement())
  posts Post[]
}

model Post {
  id       Int  @id @default(autoincrement())
  author   User @relation(fields: [authorId], references: [id])
  authorId Int
}
  • SQL
    • 注意,"authorFirstName" TEXT NOT NULL, 这里相比一对一少了 UNIQUE
CREATE TABLE "User" (
    firstName TEXT,
    lastName TEXT,
    PRIMARY KEY ("firstName","lastName")
);
CREATE TABLE "Post" (
    id SERIAL PRIMARY KEY,
    "authorFirstName" TEXT NOT NULL,
    "authorLastName" TEXT NOT NULL,
    FOREIGN KEY ("authorFirstName", "authorLastName") REFERENCES "User"("firstName", "lastName")
);

多对多

  • 两个具有多对多关系的模型,例如 CategoryPost
  • 一个模型作为关系表,例如底层数据库的 CategoriesOnPosts (有时也称为 JOIN链接(link)中间(pivot) 表)
  • 此例中,关系表模型 定义了额外的字段 来描述 Post/Category 关系 - 谁指定了此类别 (assignedBy),以及何时指定 (assignedAt):
model Post {
  id         Int                 @id @default(autoincrement())
  title      String
  categories CategoriesOnPosts[]
}

model Category {
  id    Int                 @id @default(autoincrement())
  name  String
  posts CategoriesOnPosts[]
}

model CategoriesOnPosts {
  post       Post     @relation(fields: [postId], references: [id])
  postId     Int // 关系标量字段 (在上述 `@relation` 属性中使用)
  category   Category @relation(fields: [categoryId], references: [id])
  categoryId Int // 关系标量字段 (在上述 `@relation` 属性中使用)
  assignedAt DateTime @default(now())
  assignedBy String

  @@id([postId, categoryId])
}

对应 SQL

CREATE TABLE "Category" (
    id SERIAL PRIMARY KEY
);
CREATE TABLE "Post" (
    id SERIAL PRIMARY KEY
);
-- Relation table + indexes -------------------------------------------------------
CREATE TABLE "CategoryToPost" (
    "categoryId" integer NOT NULL,
    "postId" integer NOT NULL,
    "assignedBy" text NOT NULL
    "assignedAt" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY ("categoryId")  REFERENCES "Category"(id),
    FOREIGN KEY ("postId") REFERENCES "Post"(id)
);
CREATE UNIQUE INDEX "CategoryToPost_category_post_unique" ON "CategoryToPost"("categoryId" int4_ops,"postId" int4_ops);
Licensed under CC BY-NC-SA 4.0
本博客已稳定运行
发表了53篇文章 · 总计28.17k字
使用 Hugo 构建
主题 StackJimmy 设计