メソッドチェーン

GORMのメソッドチェーン機能は、スムーズで流れるようなコーディングスタイルを実現します。次に例を示します

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

メソッドカテゴリ

GORMは、メソッドを3つの主要なカテゴリに分類します:`チェーンメソッド`、`フィニッシャーメソッド`、`新規セッションメソッド`。

チェーンメソッド

チェーンメソッドは、現在の`Statement`に`Clause`を修正または追加するために使用されます。一般的なチェーンメソッドには、以下のようなものがあります。

  • Where
  • Select
  • Omit
  • Joins
  • Scopes
  • Preload
  • `Raw` (注:`Raw`は、SQLを構築するために他のチェーン可能なメソッドと組み合わせて使用することはできません)

包括的なリストについては、GORM Chainable APIをご覧ください。また、SQLビルダーのドキュメントでは、`Clause`について詳しく説明しています。

フィニッシャーメソッド

フィニッシャーメソッドは即時実行され、SQLコマンドを生成して実行する登録済みコールバックを実行します。このカテゴリには、以下のメソッドが含まれます。

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

完全なリストについては、GORM Finisher APIを参照してください。

新規セッションメソッド

GORMは、`Session`、`WithContext`、`Debug`などのメソッドを新規セッションメソッドとして定義しています。これらのメソッドは、共有可能で再利用可能な`*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`インスタンスを安全に再利用するには、新規セッションメソッドを使用します

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:新規セッションメソッドによる安全な再利用
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`、`WithContext`、`Debug`を使用して、各論理操作のために`*gorm.DB`インスタンスを正しく初期化し、条件の汚染を防ぎ、各クエリが明確で、提供された特定の条件に基づいていることを保証します。

全体的に、これらの例は、正確で効率的なデータベースクエリを保証するために、メソッドチェーンとインスタンス管理に関してGORMの動作を理解することの重要性を示しています。

プラチナスポンサー

ゴールドスポンサー

プラチナスポンサー

ゴールドスポンサー