ORM(對象關係對映):讓資料庫操作更簡單的工具

更新日期: 2025 年 3 月 4 日

在開發應用程式時,與資料庫的互動是不可避免的。

過去,開發者需要手寫 SQL 查詢來對資料庫進行增刪改查(CRUD)操作,這種方式靈活但開發效率較低,並且容易因為不同的資料庫語法差異導致程式碼難以維護。

ORM(Object-Relational Mapping,對象關係對映) 的出現,為開發者提供了一種更直覺、更高效的方式來與資料庫交互。

它允許開發者使用程式語言中的物件來操作資料庫,而不需要直接寫 SQL,大幅提升開發效率與可維護性。

本篇文章將詳細介紹 ORM 是什麼、如何運作,以及它的優缺點,幫助初學者理解 ORM 如何簡化資料庫開發。


什麼是 ORM(對象關係對映)?

ORM(Object-Relational Mapping,對象關係對映) 是一種將程式語言中的物件(Object)與資料庫中的關係型表格(Relational Table)對應起來的技術

換句話說,ORM 讓開發者可以用物件的方法來操作資料,而不需要直接撰寫 SQL。例如:

  • Python + Django ORM
  • Java + Hibernate
  • C# + Entity Framework
  • JavaScript + Sequelize

透過 ORM,開發者可以在程式碼中像操作物件一樣操作資料庫,而 ORM 會自動轉換為 SQL 查詢,並執行相應的操作。


ORM 的起源與發明者

ORM(Object-Relational Mapping,對象關係對映)的概念,並不是由某個特定個人「發明」的,而是隨著關聯式資料庫與面向對象程式設計(OOP) 的發展,自然演進出來的一種技術。

然而,ORM 的思想可以追溯到 20 世紀 80-90 年代:

1980 年代

關聯式資料庫(Relational Database,RDB)逐漸成為企業數據存儲的標準,但當時的程式語言(如 C、COBOL)並不具有面向對象的特性,開發者需要手動撰寫 SQL 來存取數據。

1990 年代

物件導向程式設計(OOP)逐漸流行,如 Java、C++ 開始廣泛使用。

然而,關聯式資料庫仍然使用 SQL,而 OOP 語言則以「類別(Class)」和「物件(Object)」為核心,導致程式碼與資料庫之間存在「不匹配」的問題

2000 年代初

開發者開始尋找一種方式來將「關聯式資料庫」與「物件導向程式設計」結合,ORM 應運而生,提供了一種將資料表映射為程式語言中的物件的方法。

雖然 ORM 不是某個特定人「發明」的,但一些關鍵技術推動了 ORM 的發展:

  • Hibernate(2001 年,Java):由 Gavin King 開發,這是最早的 ORM 框架之一,它解決了 Java 開發者手寫 SQL 的問題。
  • Active Record(2003 年,Ruby on Rails):由 David Heinemeier Hansson(DHH) 提出的 ORM 設計模式,使得 ORM 變得更易用。
  • Entity Framework(2008 年,.NET):微軟開發的 ORM,成為 C#/.NET 開發的標準。

ORM 的運作原理

sequenceDiagram
    participant 開發者 as 開發者(應用程式)
    participant ORM as ORM框架
    participant DB as 資料庫
    
    開發者->>ORM: 透過方法呼叫查詢/保存資料
    ORM->>DB: 產生並執行 SQL
    DB-->>ORM: 回傳結果集(查詢) / 執行結果(保存)
    ORM-->>ORM: 依照映射設定,將欄位 <-> 物件屬性進行轉換
    ORM-->>開發者: 回傳轉換後的物件或執行結果

將資料表對應為程式中的類別

在使用 ORM 時,通常會為資料庫中的每個表(Table)建立一個對應的類別(Class),類別中的屬性對應到資料表的欄位。例如,在 Django ORM 中:

from django.db import models

class User(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100)
    email = models.EmailField(unique=True)

這段程式碼表示:

  • User 類別對應到資料庫中的 users 表。
  • nameemail 是對應的欄位,ORM 會自動把這些轉換為 SQL。

物件操作 → 自動轉換成 SQL

ORM 允許開發者透過物件的方法來操作資料庫,而 ORM 會在底層自動生成並執行 SQL 查詢。例如:

# 建立新使用者
user = User(name="Alice", email="[email protected]")

user.save()  
# ORM 會自動執行 
# INSERT INTO users (name, email) VALUES ('Alice', '[email protected]');

# 查詢使用者
user = User.objects.get(id=1)  
# ORM 會執行 
# SELECT * FROM users WHERE id = 1;

# 更新使用者
user.name = "Alice Smith"
user.save()  
# ORM 會執行 
# UPDATE users SET name = 'Alice Smith' WHERE id = 1;

# 刪除使用者
user.delete()  # ORM 會執行 DELETE FROM users WHERE id = 1;

開發者不需要寫 SQL,ORM 會根據程式碼的邏輯,自動產生並執行 SQL 查詢,簡化了資料庫操作。

---
title: ORM 底層運作邏輯
---
classDiagram
    direction TB  %% 由上到下,符合邏輯層次

    %% 應用層(開發者操作)
    class 開發者操作 {
        +User.save() 物件操作
        +User.objects.get(id=1) 查詢操作
        +User.delete()  刪除操作
    }

    %% ORM 處理層
    class ORM層 {
        +屬性映射: 物件欄位 ↔ 資料庫欄位
        +關聯映射: 物件關聯 ↔ 外鍵
        +SQL 生成器: 產生 SQL 指令
        +執行 SQL 查詢
    }

    %% SQL 轉換與資料庫層
    class SQL處理層 {
        +解析 ORM 指令
        +生成對應 SQL
        +執行 SQL 並回傳結果
    }

    %% 資料庫層
    class 資料庫 {
        +users 表
        +posts 表
        +儲存資料
        +返回查詢結果
    }

    %% 連結關係
    開發者操作 --> ORM層 : "操作物件"
    ORM層 --> SQL處理層 : "轉換為 SQL 指令"
    SQL處理層 --> 資料庫 : "執行 SQL"
    資料庫 --> SQL處理層 : "回傳資料"
    SQL處理層 --> ORM層 : "轉換回 ORM 物件"
    ORM層 --> 開發者操作 : "回傳物件或執行結果"

ORM 主要要解決的問題

ORM 的核心目標,是解決「關聯式資料庫」「物件導向程式設計(OOP)」之間的「不匹配問題(Impedance Mismatch)」,具體來說,ORM 要解決以下幾個主要問題:

SQL 與程式語言的「語法不匹配」

問題:

  • 關聯式資料庫使用 SQL 來存取數據,而 OOP 程式語言使用類別與物件。
  • 開發者必須手寫 SQL 查詢,這導致程式碼可讀性低,且容易因為不同資料庫的 SQL 語法不同而產生相容性問題。

解決方案: ORM 允許開發者使用程式語言中的物件方法來操作資料庫,而不用直接撰寫 SQL。例如,在 Django ORM 中:

# 創建一個新的使用者
user = User(name="Alice", email="[email protected]")
user.save()  
# ORM 自動生成 
# INSERT INTO users (name, email) VALUES ('Alice', '[email protected]');

# 查詢使用者
user = User.objects.get(id=1)  
# ORM 轉換為 
# SELECT * FROM users WHERE id = 1;

ORM 會自動生成並執行 SQL 查詢,開發者可以完全不需要寫 SQL

物件與關聯式資料表的「結構不匹配」

問題:

  • 在 OOP 中,數據是以「類別(Class)」和「物件(Object)」的形式存在,例如:
class User:
    def __init__(self, id, name, email):
        self.id = id
        self.name = name
        self.email = email
  • 但在關聯式資料庫中,數據是以「表格(Table)」的形式存儲:
CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(100)
);
  • 物件導向程式設計中的「繼承」 在 SQL 資料表中無法直接對應。

解決方案: ORM 透過映射機制(Mapping),將類別與資料表建立關聯,讓開發者可以像操作物件一樣存取資料庫:

class User(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100)
    email = models.EmailField(unique=True)

ORM 會自動處理類別與資料表之間的映射關係,開發者無需手動管理。

提高開發效率,減少重複的 SQL

問題:

  • 每次查詢資料時,都要寫 SQL,增加了開發負擔
SELECT * FROM users WHERE id = 1;
  • 如果資料庫結構變更(例如欄位名稱改變),所有 SQL 查詢都需要修改,導致維護成本上升。

解決方案: ORM 將 SQL 操作封裝成 API,開發者可以用程式語言的方法來執行 SQL:

user = User.objects.get(id=1)  # ORM 自動轉換 SQL
  • 開發者不需要重複撰寫 SQL,ORM 會根據類別結構自動調整 SQL 查詢

簡化交易控制與關聯查詢

問題:

  • 傳統 SQL 需要手動控制交易:
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;
  • 關聯式資料庫的多表關聯查詢(JOIN)語法複雜,例如:
SELECT users.name, orders.total
FROM users
JOIN orders ON users.id = orders.user_id
WHERE users.id = 1;
  • 這些操作需要開發者對 SQL 非常熟悉,且不同資料庫的 SQL 語法可能不同,影響可移植性。

解決方案: ORM 自動管理交易與關聯查詢,開發者可以透過簡單的方法處理:

# 透過 ORM 進行交易
with transaction.atomic():
    sender.balance -= 100
    receiver.balance += 100
    sender.save()
    receiver.save()

# 使用 ORM 進行關聯查詢
orders = Order.objects.filter(user__id=1)  # ORM 自動產生 JOIN 查詢

ORM 簡化了關聯查詢與交易控制,使開發者不需要手動撰寫 SQL。


為什麼要使用 ORM?

ORM 最大優勢 在於它可以提升開發效率、增加可讀性、減少錯誤。以下是 ORM 的幾個主要優點:

提高開發效率

  • 開發者不需要手寫 SQL 查詢,而是透過物件方法來操作資料庫,減少開發時間。
  • 適用於大型應用程式,避免撰寫重複的 SQL 查詢。

可讀性與維護性高

  • ORM 讓程式碼更結構化,開發者可以更直覺地理解資料庫操作,而不需要解析 SQL 查詢語句。
  • 物件導向的方式使業務邏輯更清晰。

可移植性強

  • 直接寫 SQL 可能會因為不同資料庫(MySQL、PostgreSQL、SQLite)的語法不同,導致程式碼難以跨資料庫使用
  • ORM 屏蔽了底層 SQL 的差異,讓程式碼更容易在不同資料庫之間轉換。

內建安全性

  • ORM 內建 SQL 防注入攻擊機制,自動處理 SQL 參數,避免惡意 SQL 注入攻擊。

ORM 的缺點

雖然 ORM 有許多優勢,但它並不是適用於所有情境,以下是 ORM 的幾個常見缺點:

效能可能較低

  • ORM 生成的 SQL 可能不是最優化的 SQL,在大規模數據查詢時,直接寫 SQL 可能會更高效
  • ORM 的查詢通常會自動加上許多額外的欄位,影響執行效率。

複雜查詢難以處理

  • ORM 適合簡單的 CRUD 操作,但當查詢變得非常複雜時(如多表聯查、窗口函數),可能仍需要手寫 SQL
  • 例如:
users = User.objects.raw("SELECT id, name FROM users WHERE email LIKE '%example.com%'")
  • 這種情境下,開發者仍然需要直接寫 SQL 查詢。

學習成本

  • ORM 需要學習不同的框架語法與規則,對初學者來說,可能需要一些時間適應不同 ORM 的用法。

ORM 與 SQL 手寫查詢的比較

特性ORM手寫 SQL
開發效率✅ 高,直接透過物件操作資料❌ 低,每次都需手寫 SQL
可讀性✅ 高,程式碼更直覺❌ 低,SQL 嵌入程式碼較難讀
效能❌ 可能較低✅ 高,可手動優化查詢
移植性✅ 高,支援多種資料庫❌ 低,不同資料庫 SQL 語法不同
安全性✅ 自動防 SQL 注入❌ 需要手動處理安全性

ORM 適用場景

適合

  • 快速開發 Web 應用程式(如 Django、Flask、Spring Boot)
  • 小型專案與原型開發
  • 需要跨資料庫的應用
  • CRUD 為主的應用

不適合

  • 需要高效能的應用(如大規模數據分析、金融交易系統)
  • 查詢邏輯非常複雜的應用(可能仍需手寫 SQL)

結論

ORM 透過物件來映射關聯式資料庫,使開發者可以不用寫 SQL,透過程式語言的方式進行資料庫操作。這使開發變得更快速、直覺,也提高了程式的可讀性與可維護性。

然而,ORM 並不是萬能的,當涉及到效能優化或複雜查詢時,仍然可能需要手寫 SQL。

因此,最好的方式通常是結合 ORM 與 SQL,在日常開發中使用 ORM 提高效率,而在高效能需求場景下直接使用 SQL。

如果你是初學者,推薦你先從 ORM 開始學習,熟悉基礎後,再學習 SQL 的最佳實踐! 🚀

Similar Posts