方法链

原文:https://gorm.io/docs/method_chaining.html

GORM allows method chaining, so you can write code like this:

​ GORM允许方法链,因此你可以这样写代码:

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

There are three kinds of methods in GORM: Chain Method, Finisher Method, New Session Method.

​ GORM有三种方法:Chain MethodFinisher MethodNew Session Method

After a Chain method, Finisher Method, GORM returns an initialized *gorm.DB instance, which is NOT safe to reuse anymore, or new generated SQL might be polluted by the previous conditions, for example:

​ 在Chain method之后,Finisher Method,GORM返回一个初始化的*gorm.DB实例,这个实例不能再被重用,或者新的SQL可能会受到之前条件的污染,例如:

1
2
3
4
5
6
7
queryDB := DB.Where("name = ?", "jinzhu")

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

queryDB.Where("age > ?", 20).First(&user2)
// SELECT * FROM users WHERE name = "jinzhu" AND age > 10 AND age > 20

In order to reuse a initialized *gorm.DB instance, you can use a New Session Method to create a shareable *gorm.DB, e.g:

​ 为了重用一个初始化的*gorm.DB实例,你可以使用New Session Method创建一个可共享的*gorm.DB,例如:

1
2
3
4
5
6
7
queryDB := DB.Where("name = ?", "jinzhu").Session(&gorm.Session{})

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

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

Chain方法 Chain Method

Chain methods are methods to modify or add Clauses to current Statement, like:

​ Chain方法是用于修改或添加Clauses到当前Statement的方法,例如:

Where, Select, Omit, Joins, Scopes, Preload, Raw (Raw can’t be used with other chainable methods to build SQL)…

WhereSelectOmitJoinsScopesPreloadRawRaw不能与其他可链接的方法一起构建SQL)…

Here is the full lists, also check out the SQL Builder for more details about Clauses.

​ 这里有一个完整的列表,也可以查看SQL Builder以获取更多关于Clauses的详细信息。

Finisher方法 Finisher Method

Finishers are immediate methods that execute registered callbacks, which will generate and execute SQL, like those methods:

​ Finishers是立即执行已注册回调的方法,它们将生成并执行SQL,例如这些方法:

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

CreateFirstFindTakeSaveUpdateDeleteScanRowRows

Check out the full lists here.

​ 请查看完整列表

New Session Method

GORM defined Session, WithContext, Debug methods as New Session Method, refer Session for more details.

​ GORM定义了SessionWithContextDebug方法作为New Session Method,参考Session以获取更多详细信息。

After a Chain method, Finisher Method, GORM returns an initialized *gorm.DB instance, which is NOT safe to reuse anymore, you should use a New Session Method to mark the *gorm.DB as shareable.

​ 在Chain methodFinisher Method之后,GORM返回一个初始化的*gorm.DB实例,这个实例不能再被重用,你应该使用New Session Method将其标记为可共享。

Let’s explain it with examples:

​ 让我们通过示例来解释:

示例1 :Example 1:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
// db是一个新初始化的`*gorm.DB`实例,它是安全的可以重用的 db is a new initialized `*gorm.DB`, which is safe to reuse

db.Where("name = ?", "jinzhu").Where("age = ?", 18).Find(&users)
// Where("name = ?", "jinzhu")`是第一个链方法调用,它创建了一个初始化的`*gorm.Statement`实例,也就是`*gorm.DB` `Where("name = ?", "jinzhu")` is the first chain method call, it will create an initialized `*gorm.DB` instance, aka `*gorm.Statement`
// `Where("age = ?", 18)`是第二个链方法调用,它重用了上面的`*gorm.Statement`,向其添加了新的条件`age = 18` `Where("age = ?", 18)` is the second chain method call, it reuses the above `*gorm.Statement`, adds new condition `age = 18` to it
// `Find(&users)`是一个完成器方法,它执行已注册的查询回调,生成并运行以下SQL: `Find(&users)` is a finisher method, it executes registered Query Callbacks, which generates and runs the following SQL:
// SELECT * FROM users WHERE name = 'jinzhu' AND age = 18;

db.Where("name = ?", "jinzhu2").Where("age = ?", 20).Find(&users)
// `Where("name = ?", "jinzhu2")`也是第一个链方法调用,它创建了一个新的`*gorm.Statement` `Where("name = ?", "jinzhu2")` is also the first chain method call, it creates a new `*gorm.Statement`
// `Where("age = ?", 20)`重用了上面的`Statement`,并向其添加了条件 `Where("age = ?", 20)` reuses the above `Statement`, and add conditions to it
// `Find(&users)`是一个完成器方法,它执行已注册的查询回调,生成并运行以下SQL: `Find(&users)` is a finisher method, it executes registered Query Callbacks, generates and runs the following SQL:
// SELECT * FROM users WHERE name = 'jinzhu2' AND age = 20;

db.Find(&users)
// `Find(&users)`是一个完成器方法调用,它也创建了一个新的`Statement`并执行了已注册的查询回调,生成并运行以下SQL: `Find(&users)` is a finisher method call, it also creates a new `Statement` and executes registered Query Callbacks, generates and runs the following SQL:
// SELECT * FROM users;

(不好的)示例2: (Bad) Example 2:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
// db是一个新初始化的*gorm.DB实例,它是安全的可以重用的 db is a new initialized *gorm.DB, which is safe to reuse

tx := db.Where("name = ?", "jinzhu")
// `Where("name = ?", "jinzhu")`返回一个初始化的`*gorm.Statement`实例后在链方法`Where`之后,这是不安全的,不能重用 `Where("name = ?", "jinzhu")` returns an initialized `*gorm.Statement` instance after chain method `Where`, which is NOT safe to reuse

// good case
tx.Where("age = ?", 18).Find(&users)
// `tx.Where("age = ?", 18)`使用上述的`*gorm.Statement`,向其添加了新条件 `tx.Where("age = ?", 18)` use the above `*gorm.Statement`, adds new condition to it
// `Find(&users)`是一个完成器方法调用,它执行已注册的查询回调,生成并运行以下SQL: `Find(&users)` is a finisher method call, it executes registered Query Callbacks, generates and runs the following SQL:
// SELECT * FROM users WHERE name = 'jinzhu' AND age = 18

// bad case
tx.Where("age = ?", 28).Find(&users)
// `tx.Where("age = ?", 28)`也使用上述的`*gorm.Statement`,并继续添加条件 `tx.Where("age = ?", 28)` also use the above `*gorm.Statement`, and keep adding conditions to it
// 所以下面的生成的SQL被之前的条件污染了: So the following generated SQL is polluted by the previous conditions:
// SELECT * FROM users WHERE name = 'jinzhu' AND age = 18 AND age = 28;

示例3:Example 3:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
// db是一个新初始化的*gorm.DB实例,它是安全的可以重用的 db is a new initialized *gorm.DB, which is 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`返回`*gorm.DB`标记为安全可以重用,基于它的新初始化的`*gorm.Statement`保持当前条件 `Session`, `WithContext`, `Debug` returns `*gorm.DB` marked as safe to reuse, newly initialized `*gorm.Statement` based on it keeps 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;
最后修改 October 10, 2024: 更新 (a4b8f85)