什麼是 ORM?應用程式如何與資料庫溝通,一次看懂
ORM(物件關聯對映)是位於應用程式與關聯式資料庫之間的程式庫。開發者不必用 SQL 寫資料庫查詢,而是用程式語言中的一般物件來處理資料,例如 db.booking.create(...) 或 Booking.find(...)。ORM 會把這些操作轉換成 SQL、執行,再把結果變回物件。常見的例子有 TypeScript 的 Prisma 與 Drizzle、Python 的 SQLAlchemy,以及 C# 的 Entity Framework Core。
用 AI 開發時,為什麼 ORM 很重要
當 AI 應用程式建構工具替你的應用程式加上資料庫時,通常也會順便加上一個 ORM 來和它溝通。你不必自己寫 ORM 程式碼,但知道它的存在很有幫助:
- 你的資料模型存放在程式碼裡。 ORM 的 schema 檔通常是描述應用程式資料最清楚的文件:有哪些資料表、每個資料表有哪些欄位,以及它們之間如何連結。讀一下它,就能快速確認 AI 是否理解你的需求。
- 資料庫的變更都透過遷移完成。 當你要求「替客戶加上電話號碼」時,AI 會更新模型並建立一份遷移檔。了解這點,就能明白為什麼有些變更要先套用到資料庫,功能才會在正式環境生效。
- 預設就比較安全。 ORM 組合查詢的方式可以防範 SQL 注入攻擊,而手動拼接查詢正是應用程式最常見的安全漏洞之一。
- 效能陷阱。 ORM 很容易不小心就執行上百次小查詢,而原本一次就能完成。這是 AI 開發的應用程式頁面變慢的常見原因。
日常生活的比喻
想像一位英國旅客和一位日本店家,彼此語言不通,透過翻譯溝通。
旅客(你的應用程式)說:「我想要你們最便宜的三種茶。」翻譯(ORM)把這句話精準地翻成日文(SQL),交給店家(資料庫),再把答覆翻回英文。
旅客不必學日文,大多數對話都沒問題。但遇到複雜的協商時,直接開口溝通會比較好,所以大多數 ORM 也允許開發者在需要時直接寫原生 SQL。
ORM 如何運作
像 Postgres 這類資料庫,會把資料存在由列和欄組成的資料表中,並用 SQL 查詢。程式語言則以物件來運作:例如一筆有 date、customer 和 status 的預約。ORM 負責在兩者之間對映:
| 資料庫端 | ORM/程式端 |
|---|---|
資料表 bookings | 模型 Booking |
| 資料列 | 一個預約物件 |
欄位 starts_at | 屬性 startsAt |
外部鍵 customer_id | 關聯 booking.customer |
SELECT、INSERT、UPDATE、DELETE | find、create、update、delete 方法 |
這四種操作就是幾乎所有應用程式都建立在上面的 CRUD 動作。
實例:用 Prisma 處理預約
以下是一個簡化的 Prisma schema,描述美髮沙龍預約應用程式的兩個資料表以及它們的連結方式:
model Customer {
id Int @id @default(autoincrement())
name String
email String @unique
bookings Booking[]
}
model Booking {
id Int @id @default(autoincrement())
startsAt DateTime
service String
customer Customer @relation(fields: [customerId], references: [id])
customerId Int
}
白話來說:一位客戶有姓名、不重複的電子郵件,以及多筆預約;每筆預約有開始時間、服務項目,並且屬於一位客戶。
現在應用程式想要查「Lena 即將到來的預約,最近的排在最前面」:
const bookings = await db.booking.findMany({
where: {
customer: { email: "lena@example.com" },
startsAt: { gte: new Date() },
},
orderBy: { startsAt: "asc" },
});
ORM 會把它轉換成大致如下的 SQL,執行後回傳一串預約物件:
SELECT b.* FROM "Booking" b
JOIN "Customer" c ON c.id = b."customerId"
WHERE c.email = $1 AND b."startsAt" >= $2
ORDER BY b."startsAt" ASC;
$1 和 $2 是佔位符:電子郵件和日期會與查詢文字分開傳送,這正是防止 SQL 注入的關鍵。
遷移
接著如果你要求「讓客戶可以新增電話號碼」,AI 會在 Customer 模型中加入 phone String?(? 代表選填),並產生一份遷移,也就是類似 ALTER TABLE "Customer" ADD COLUMN "phone" TEXT; 的 SQL 腳本。遷移會按順序保存,因此每一份資料庫都能被更新到相同的結構,而且變更歷史也會被保留。
各語言常見的 ORM
| 語言 | 常見 ORM |
|---|---|
| TypeScript/JavaScript | Prisma、Drizzle、TypeORM、Sequelize |
| Python | SQLAlchemy、Django ORM、SQLModel |
| C# | Entity Framework Core |
| Java | Hibernate(常透過 Spring Data JPA 使用) |
| Ruby | Active Record |
ORM 隱藏 SQL 的程度各不相同。Prisma 使用自己的 schema 語言和查詢風格;Drizzle 則刻意保留接近 SQL 的寫法,同時維持完整的型別。另外有一類較輕量的工具叫做查詢建構器(query builder),例如 TypeScript 的 Knex 或 Kysely,它們幫你在程式中組出 SQL,但不會把資料列完整對映成物件。
關鍵名詞
| 名詞 | 意義 |
|---|---|
| 模型(Model) | 資料表及其欄位在程式中的定義。 |
| Schema | 所有資料表、欄位與關係的完整描述。 |
| 關聯(Relation) | 模型之間的連結,例如一筆預約屬於某位客戶。 |
| 遷移(Migration) | 有版本編號、用來修改資料庫結構的腳本。 |
| 查詢建構器(Query builder) | 在程式中組出 SQL、但不做完整物件對映的較輕量工具。 |
| N+1 問題 | 先查出一份清單,再對每個項目各查一次——資料量大時會很慢。 |
| 原生 SQL(Raw SQL) | 手寫的 SQL,當 ORM 礙事時使用。 |
常見的誤解
- 「ORM 就是資料庫。」 不是。它是翻譯器。你仍然需要像 Postgres 這樣的資料庫。
- 「用了 ORM 就不必了解你的資料。」 設計不良的資料表,透過 ORM 操作一樣很痛苦。好的資料模型比工具本身更重要。
- 「ORM 一定很慢。」 日常查詢通常沒問題。變慢通常來自 N+1 查詢或缺少索引等模式,而這些都是可以修正的。
- 「用 ORM 就永遠不會有 SQL 注入風險。」 標準的 ORM 方法是安全的,但如果把使用者輸入直接貼進手寫的原生 SQL,仍然很危險。
- 「修改 schema 檔就會改變正式的資料庫。」 只有在建立遷移並套用到該資料庫之後才會生效。
該問你的 AI 建構工具什麼
- 「給我看資料庫的 schema,並用白話解釋每個資料表和關係。」
- 「這個專案用的是哪一套 ORM?遷移檔放在哪裡?」
- 「在修改任何資料表之前,先告訴我既有資料會不會受影響;有資料的欄位不要在未經詢問的情況下刪除。」
- 「檢查最慢的頁面是否有 N+1 查詢,並在列表被篩選或排序的欄位上加上索引。」
- 「確保每一個使用使用者輸入的查詢都經過 ORM 或使用參數,不要用字串拼接 SQL。」
Mythex 中的 ORM
當你的應用程式需要儲存資料時,Mythex 會為專案加上專屬的 Postgres 資料庫(在聊天中詢問,或使用 /database 指令),並把連線資訊注入工作區與已發布的應用程式(資料庫說明)。接下來由代理程式撰寫讀取和儲存資料的程式碼。如果你有偏好,例如「使用 Prisma」、「使用 SQLAlchemy」或「只用原生 SQL,不要 ORM」,直接在聊天中說明即可。隨時都可以要求它帶你瀏覽 schema;你也可以在程式碼編輯器中直接閱讀檔案。想了解更完整的架構,請參考什麼是資料庫與 SQL 與 NoSQL 的比較。
常見問題
用簡單的話說,什麼是 ORM?
ORM(物件關聯對映,object-relational mapper)是位於應用程式和關聯式資料庫之間的程式庫。開發者可以用程式語言中的一般物件來讀寫資料,而 ORM 會在背後替他們寫好 SQL 查詢。
常見的 ORM 有哪些?
常見的 ORM 包括:TypeScript 與 JavaScript 的 Prisma 和 Drizzle、Python 的 SQLAlchemy 與 Django ORM、C# 的 Entity Framework Core、Java 的 Hibernate,以及 Ruby on Rails 的 Active Record。
ORM 比直接寫 SQL 好嗎?
要看用途。ORM 讓日常的讀寫更快寫、更安全、也更容易修改;而手寫 SQL 能完全掌控複雜報表或對效能要求高的查詢。大多數 ORM 在需要時都能直接改寫成原生 SQL。
什麼是遷移(migration)?
遷移是一段小型、有版本編號的腳本,用來修改資料庫的結構,例如新增一個資料表或一個欄位。ORM 可以根據你的資料模型產生遷移檔,讓每一份資料庫(筆電上的、測試環境的、正式環境的)都維持相同的結構。