Prisma 入門指南

janlin002
11 min readDec 21, 2023

什麼是 Prisma?

蠻推薦各位可以去看這部影片,短短 50 分鐘,把 Prisma 精華都講過一遍了

Nest 官網是這樣描述 Prisma 的

Prisma is an open-source ORM for Node.js and TypeScript. It is used as an alternative to writing plain SQL, or using another database access tool such as SQL query builders (like knex.js) or ORMs (like TypeORM and Sequelize). Prisma currently supports PostgreSQL, MySQL, SQL Server, SQLite, MongoDB and CockroachDB (Preview).

那我們用 chatGPT 來翻譯一下

Prisma 是用於Node.js和TypeScript的開源ORM(對象-關係映射)。它被用作替代編寫純SQL或使用其他數據庫訪問工具(如knex.js)或ORM(如TypeORM和Sequelize)。Prisma目前支持PostgreSQL、MySQL、SQL Server、SQLite、MongoDB和CockroachDB。

那麼新的問題來了,什麼是 ORM?

什麼是 ORM?

在過去後端在對資料庫操作時,都需要寫一些 SQL 語言,來跟資料庫互動,不過這樣有些缺點

1. 程式碼會變得比較難以維護

2. 容易寫錯,例如:空行不對,缺少引號

3. 容易遭到 SQL Injection 攻擊

為了解決以上問題,就出現了 ORMORM 不在需要自己去寫 SQL 語法,而是使用 OOP 的概念去撰寫

sql 語法

SELECT * FROM TABLE

ORM 語法

this.prisma.table.findMany();

當然 ORM 也不是沒有缺點,由於需要在背後大量的轉換 SQL 語法,導致效能上也比直接操作 SQL 來的更慢一些

對 ORM 有興趣的讀者,可以參考這篇文章

總的來說 Prisma 就是一個可以讓我們用 OOP 概念去操作資料庫的套件,除了這次要介紹的 Prisma 之前我們介紹過的 TypeORM 也是在做一樣的事情

建立 Nest 專案

$ npm i -g @nestjs/cli
$ nest new [project-name]

建立完專案以後,試著把專案 run 起來,確定沒有問題

$ npm run start:dev

Docker + PostgreSql

這邊如果有任何錯誤,都歡迎留言給我,十分感謝

首先線建立一個 docker-compose.yml 資料夾

touch docker-compose.yml

不知道 Docker compose 的讀者,可以看這篇文章

並且輸入以下程式碼

version: '3.1'
services:
postgres:
container_name: postgres
image: postgres:13.5
restart: always
ports:
- 5432:5432
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
PGDATA: ./pgdata:/var/lib/postgresql/data/pgdata
  • image 裡面 postgres 的版本可以自己選擇,可參考 postgres 的 DockerHub
  • port 分為兩部分host_portcontainer_port,以上方程式碼可解讀成: 你將主機的連接埠 5432 對應到 postgres 容器的連接埠 5432。 (5432 通常是 PostgreSQL 使用的連接埠)

接著我們需要透過指令構建 image 並執行 container

docker-compose up

環境架設起來後,接著就可以到 pgAdmin 裡面做連線了

對 docker 連線 PostgreSql 有興趣的讀者,可以參考這篇文章

Set up Prisma

推薦大家在開發 Prisma 時,一定要下載 vscode Prisma 套件

資料庫架設好以後,我們接著架設我們的 ORM

$ npm install prisma - save-dev
$ npx prisma init

這時候會發先我們多了兩個資料夾:

1. prisma:database schema 會寫在這裡

2. .env:環境變數

接著我們需要將 Prisma 跟 PostgreSql 做連線

我們需要到 .env 資料夾中,更改 DATABASE_URL

DATABASE_URL = "postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public";

這邊的寫法跟剛剛連線的寫法一樣

postgresql://USER:PASSWORD@HOST:PORT/DATABASE

到這邊基本的連線就已經完成

Prisma service

透過 Prisma service 可以實例化(instance) PrismaClient 並且連結到資料庫

$ npx nest g module prisma
$ npx nest g service prisma

這邊有個小技巧: 假設你沒有寫測試的習慣,且不想要每次都自動生成一堆測試檔案,可以在指令後方加上 — no-spec

$ npx nest g module prisma - no-spec
$ npx nest g service prisma - no-spec
// src/prisma/prisma.service.ts
import { INestApplication, Injectable } from "@nestjs/common";
import { PrismaClient } from "@prisma/client";
@Injectable()
export class PrismaService extends PrismaClient {}
// src/prisma/prisma.module.ts
import { Module } from "@nestjs/common";
import { PrismaService } from "./prisma.service";
@Module({
providers: [PrismaService],
exports: [PrismaService],
})
export class PrismaModule {}

實戰篇

Database

這是我們是以一個班級的作答情況,來設計這個 database,下面會以這個情境來說明常見的 relations

relations

one-to-one

one-to-many

一對多關係,以上面的圖片來說,一個學生會有多個測驗結果,或是說一個課堂中會有多個測驗,這個關係就是 1-n

many-to-may

多對多,就好像學生跟課堂間的關係

schema

特殊語法

@@map / @map

這兩個 map 都是拿來重命名,@map 是針對 Column 重命名,而 @@map 是針對 table 重命名

model User {
id Int @id
cardId Int @map("card_id")
@@map("user")
}

等同於:

model user {
id Int @id
card_id Int
}

@default

預設值

model User {
id Int @id @default(autoincrement())
}

autoincrement() 代表自動生成

@id / @@id

@id 代表主鍵(PK),@@id 則是一次設立多個主鍵

model Table {
id Int @id @default(autoincrement())
}
model Table {
firstName String
lastName String
@@id([firstName, lastName])
}

@unique / @@unique

跟 id 一樣,分為一個跟多個唯一值

model User {
id Int @id @default(autoincrement())
email String? @unique
name String
}
model User {
id Int @id
first_name Int
last_name Int
card Int?

@@unique([first_name, last_name])
}

@relation

relation 代表的是外鍵約束

寫法如下

model User {
id Int @id
first_name String
last_name String
Post Post[]
}
model Post {
id Int @id
author User @relation(fields: [userId], references: [id])
content String
userId Int
}

感覺很難懂,但是其實很間單,把他拆分一下

author User @relation(fields: [userId], references: [id])
author [要連結的table] @relation(fields: [自己的哪個Column要做連線], references: [要連到目標table的哪個Column])

這樣是不是簡單很多?

結語

花了幾天玩了一下 Prisma 個人覺得寫法比 TypeORM 更為直觀,並且 vscode prisma 套件太強大了,錯誤訓息也非常人性化,大推~

參考文章

https://blog.dteam.top/posts/2022-01/prisma-introduction.html

--

--