方法鏈接

GORM 的方法鏈接功能可讓編碼風格流暢且順利。以下是範例

db.Where("name = ?", "jinzhu").Where("age = ?", 18).First(&user)

方法分類

GORM 將方法分為三個主要分類:鏈接方法完成方法新階段方法

鏈接方法

鏈接方法用於修改或附加子句至目前的陳述。一些常見的鏈接方法包括

  • Where
  • Select
  • Omit
  • Joins
  • Scopes
  • Preload
  • Raw (注意:Raw 不能與其他可鏈接方法結合使用來建置 SQL)

如需完整清單,請瀏覽 GORM 可鏈接 API。此外,SQL 建構器 文件提供有關子句的更多詳細資訊。

完成方法

完成方法是立即執行的,執行已註冊的回呼,以產生並執行 SQL 指令。此分類包括方法

  • Create
  • First
  • Find
  • Take
  • Save
  • Update
  • Delete
  • Scan
  • Row
  • Rows

如需完整清單,請參閱 GORM 完成器 API

新階段方法

GORM 定義了方法,例如 SessionWithContextDebug,作為新階段方法,這對於建立可共用且可重複使用的 *gorm.DB 執行個體至關重要。如需更多詳細資訊,請參閱 階段 文件。

可重複使用性和安全性

GORM 的一個重要面向是了解何時可以安全重複使用 *gorm.DB 執行個體。在 鏈接方法完成方法 之後,GORM 會傳回已初始化的 *gorm.DB 執行個體。此執行個體不適合重複使用,因為它可能會繼承前一次操作的條件,進而導致 SQL 查詢受到污染。例如

不安全重複使用的範例

queryDB := DB.Where("name = ?", "jinzhu")

// First query
queryDB.Where("age > ?", 10).First(&user)
// SQL: SELECT * FROM users WHERE name = "jinzhu" AND age > 10

// Second query with unintended compounded condition
queryDB.Where("age > ?", 20).First(&user2)
// SQL: SELECT * FROM users WHERE name = "jinzhu" AND age > 10 AND age > 20

安全重複使用的範例

若要安全重複使用 *gorm.DB 執行個體,請使用新的 Session 方法

queryDB := DB.Where("name = ?", "jinzhu").Session(&gorm.Session{})

// First query
queryDB.Where("age > ?", 10).First(&user)
// SQL: SELECT * FROM users WHERE name = "jinzhu" AND age > 10

// Second query, safely isolated
queryDB.Where("age > ?", 20).First(&user2)
// SQL: SELECT * FROM users WHERE name = "jinzhu" AND age > 20

在這個情況下,使用 Session(&gorm.Session{}) 可確保每個查詢都從新的內容開始,防止 SQL 查詢受到先前操作條件的污染。這對於維護資料庫互動的完整性和準確性至關重要。

範例說明

讓我們透過幾個範例來釐清

  • 範例 1:安全執行個體重複使用
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
// 'db' is a newly initialized `*gorm.DB`, which is safe to reuse.

db.Where("name = ?", "jinzhu").Where("age = ?", 18).Find(&users)
// The first `Where("name = ?", "jinzhu")` call is a chain method that initializes a `*gorm.DB` instance, or `*gorm.Statement`.
// The second `Where("age = ?", 18)` call adds a new condition to the existing `*gorm.Statement`.
// `Find(&users)` is a finisher method, executing registered Query Callbacks, generating and running:
// SELECT * FROM users WHERE name = 'jinzhu' AND age = 18;

db.Where("name = ?", "jinzhu2").Where("age = ?", 20).Find(&users)
// Here, `Where("name = ?", "jinzhu2")` starts a new chain, creating a fresh `*gorm.Statement`.
// `Where("age = ?", 20)` adds to this new statement.
// `Find(&users)` again finalizes the query, executing and generating:
// SELECT * FROM users WHERE name = 'jinzhu2' AND age = 20;

db.Find(&users)
// Directly calling `Find(&users)` without any `Where` starts a new chain and executes:
// SELECT * FROM users;

在這個範例中,每個方法呼叫鏈都是獨立的,可確保乾淨、未受污染的 SQL 查詢。

  • (不良)範例 2:不安全執行個體重複使用
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
// 'db' is a newly initialized *gorm.DB, safe for initial reuse.

tx := db.Where("name = ?", "jinzhu")
// `Where("name = ?", "jinzhu")` initializes a `*gorm.Statement` instance, which should not be reused across different logical operations.

// Good case
tx.Where("age = ?", 18).Find(&users)
// Reuses 'tx' correctly for a single logical operation, executing:
// SELECT * FROM users WHERE name = 'jinzhu' AND age = 18

// Bad case
tx.Where("age = ?", 28).Find(&users)
// Incorrectly reuses 'tx', compounding conditions and leading to a polluted query:
// SELECT * FROM users WHERE name = 'jinzhu' AND age = 18 AND age = 28;

在這個不良範例中,重複使用 tx 變數會導致複合條件,這通常是不需要的。

  • 範例 3:使用新的 Session 方法安全重複使用
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
// 'db' is a newly initialized *gorm.DB, safe to reuse.

tx := db.Where("name = ?", "jinzhu").Session(&gorm.Session{})
tx := db.Where("name = ?", "jinzhu").WithContext(context.Background())
tx := db.Where("name = ?", "jinzhu").Debug()
// `Session`, `WithContext`, `Debug` methods return a `*gorm.DB` instance marked as safe for reuse. They base a newly initialized `*gorm.Statement` on the current conditions.

// Good case
tx.Where("age = ?", 18).Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' AND age = 18

// Good case
tx.Where("age = ?", 28).Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' AND age = 28;

在這個範例中,使用新的 Session 方法 SessionWithContextDebug 可正確初始化 *gorm.DB 執行個體以進行每個邏輯操作,防止條件污染並確保每個查詢都是不同的,且基於提供的特定條件。

總體而言,這些範例說明了了解 GORM 在方法鏈接和執行個體管理方面的行為,以確保準確且有效率的資料庫查詢的重要性。

白金贊助商

黃金贊助商

白金贊助商

黃金贊助商