跳至主要内容

Prisma ORM with MySQL

Prisma 官方的文件很多也有點複雜,整理幾個初學比較重要的觀念跟指令。

與DB 架構互動 - Work Flow

Data modeling with Prisma ORM

簡單來說分成兩種流程

Only Prisma Client ( Pull + Generate )

prisma db pull
從 DB 映射到 Prisma:如果你的 DB 已經有結構,這個指令會把既有的結構轉換為 Prisma 的 ORM schema,顯示在 schema.prisma 裡。

prisma generate
根據 schema.prisma 生成 ORM 程式碼,使 Prisma Client 可以進行 CRUD,因此 Prisma Client 是類似於前端 lib 的存在。只要更新過 schema.prisma ,就必須重新 prisma generate 來取得最新資料。

npx prisma db pull
npx prisma generate

Prisma Migrate

prisma migrate
當我們是手動更新 schema.prisma,就必須 prisma migrate DB,所以 migrate 跟 pull 是相反的操作。
要注意 migrate 分成 dev 跟 prod 環境 !

prisma generate
完成 migrate 後,接下來要重新生成 ORM 的架構,動作跟上面的 prisma generate 說明一樣。

npx prisma migrate dev # 開發時,加上 --force-reset 參數,它會清空資料庫並重新創建資料表,這對於開發過程中的資料結構調整非常有用。
npx prisma generate
備註

如果 schema.prisma 的更新沒有動到資料庫架構,只需要執行 prisma generate

Prisma Push

除了 prisma migrateprisma push也可以用來將 Prisma 架構寫入 DB,但不同之處在於 migrate 會產生新的 migration 檔,

Deploy

還沒部署,部署後再來補充 (未完成)

npx prisma migrate deploy

Reset

npx prisma migrate reset # 會清空資料庫,包括表格,小心服用

enum 錯誤

因為 Prisma enum 宣告只能用英文、數字

enum matches_status {
// 未進行 @map("未進行")
// 進行中 @map("進行中")
// 已完成 @map("已完成")
// 已取消 @map("已取消")
}

enum matches_status {
NOT_STARTED
IN_PROGRESS
COMPLETED
CANCELED
}

若一定要用中文,可以使用 @map

model Match {
id Int @id @default(autoincrement())
matchStatus MatchStatus @map("matches_status")
}

Prisma Client

當 Prisma Schema 與 DB 的架構都同步後,我們就可以開始來操作了!

Prisma 會協助處理與資料庫的連線,因此就不需要特別調用 db.connect() 之類的方法。

這邊比較原本用 MySQL 庫跟使用 Prisma 的差別:
用 MySQL lib 的話,必須先建立連線,再以 SQL 語法與 DB 溝通。

mysql
import { RowDataPacket } from 'mysql2';
import { connection } from 'src/database'; // 負責連接到 DB 的 file

export async function getTeams() {
// although res is an Array, defining the type is need
const [res] = await connection.query<RowDataPacket[]>('SELECT * FROM teams');
return res;
}

export async function addTeams() {
try {
await connection.query<RowDataPacket[]>('SELECT * FROM teams');
} catch (e) {
console.error('addTeams SQL Error', e);
}
}

用 PrismaClient instance 與 DB 溝通,不用管連線問題

prisma
import { PrismaClient, Prisma } from '@prisma/client';

const prisma = new PrismaClient();

export async function getTeams() {
return await prisma.teams.findMany();
}

export const addTeam = async ({name,logo,}) => {
const teamSelect: Prisma.teamsSelect = {
id: true,
name: true,
};

const resp = await prisma.teams.create({
data: {
name,
...(logo && { logo }), // 有 logo 再新增 key-value
},
select: teamSelect, // 使用 select 限制返回欄位
});

return resp;
};

Prisma Type

Prisma Client 會自動生成所有表單的欄位 Type,這個型別根據 schema.prisma,因此只有資料庫結構改動過,務必要重新 prisma generate

Prisma CRUD

記幾個重要的 CRUD method

select、where

相當於 SQL 語法的 SELECTWHERE
當你不需要整個資料表的所有欄位時,可以使用 select 來指定只返回特定的欄位。這可以減少不必要的數據傳輸,提升性能。
where 一樣是條件作用

const userEmail: Prisma.UserSelect = {
email: true, // 只選擇 email 欄位
};

const user = await prisma.user.findUnique({
where: { id: 1 },
select: userEmail,
});

console.log(user); // { email: "user@example.com" }

include

關聯表格的資料可以跟著主表一起獲得,也就是經由外鍵連結的資料

const getUser = await prisma.user.findUnique({
where: {
id: 1,
},
include: {
posts: { // 包含與 user 關聯的 posts 資料
select: {
title: true, // 只選擇每篇 post 的 title
},
},
},
});

// 回傳值類似
{
id: 1,
name: "Alice",
posts: [
{ title: "My First Post" },
{ title: "Prisma Rocks" },
]
}