什么是链式调用
链式调用(也称为链式方法)是一种编程风格,它允许你通过将多个方法调用链接在一起来执行一系列操作。在 GORM 中,链式调用通常被用来构建查询条件。
例如,下面是一个使用链式调用来构建查询条件的例子:
db.Where("name = ?", "jinzhu").Where("age > ?", 10).First(&user)
在上面的例子中,我们使用了两个 Where
方法来构建查询条件。第一个 Where
方法用于指定 name
字段的值,第二个 Where
方法用于指定 age
字段的值。最后,我们调用了 First
方法来执行查询。
链式调用的优点在于它可以让你的代码更加简洁易读。你可以通过将多个方法调用链接在一起来清晰地表达你的意图。
链式调用的坑
在 GORM 中,当你使用链式方法(例如 Where
、Select
、Omit
等)时,它们会返回一个新的 *gorm.DB
实例。这个新实例包含了之前调用链式方法时设置的条件。如果你再次使用这个实例调用链式方法,那么新的条件会被添加到之前的条件中。
这意味着,如果你重复使用同一个 *gorm.DB
实例,那么新生成的 SQL 可能会被先前的条件污染。因此,我们不建议重复使用同一个 *gorm.DB
实例。
例如:
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
在上面的例子中,我们重复使用了 queryDB
这个 *gorm.DB
实例。因此,在第二次调用 Where
方法时,新的条件 age > 20
被添加到了之前的条件中。
为了避免这种情况,你可以使用 Session
方法来创建一个新的 *gorm.DB
实例,然后在这个新实例上调用链式方法。例如:
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
在上面的例子中,我们使用了 Session
方法来创建一个新的 *gorm.DB
实例。因此,在第二次调用 Where
方法时,新的条件 age > 20
没有被添加到之前的条件中。和new bing一样,每次都开启了都清除了记忆并开启了一个新的会话
可共享的 *gorm.DB
可共享的 *gorm.DB 是指一个可以安全地重复使用的 *gorm.DB 实例。在 GORM 中,您可以使用新建会话方法来创建一个可共享的 *gorm.DB 实例。例如:
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
在这个示例中,我们使用了 Session 方法来创建一个可共享的 *gorm.DB 实例。您也可以使用 WithContext 或 Debug 方法来创建可共享的实例。
哪些方法后不能使用链式调用?
在 GORM 中,当你调用 Finisher
方法(例如 Create
、First
、Find
、Take
、Save
、Update
、Delete
、Scan
、Row
和 Rows
等)时,它们会立即执行注册回调,然后生成并执行 SQL。这意味着,在调用 Finisher
方法之后,你不能再使用链式方法来修改查询条件。
例如:
db.Where("name = ?", "jinzhu").First(&user).Where("age > ?", 10)
在上面的例子中,我们在调用 First
方法之后又调用了 Where
方法。但是,这样做是无效的,因为 First
方法是一个 Finisher
方法,它会立即执行注册回调并生成 SQL。
如果你想在调用 Finisher
方法之后继续使用链式方法,那么你应该使用 Session
方法来创建一个新的 *gorm.DB
实例,然后在这个新实例上调用链式方法。例如:
db.Where("name = ?", "jinzhu").First(&user) db.Session(&gorm.Session{}).Where("age > ?", 10).First(&user2) // 对应执行的SQL语句 // SELECT * FROM users WHERE name = "jinzhu" LIMIT 1 // SELECT * FROM users WHERE age > 10 LIMIT 1
在上面的例子中,我们使用了 Session
方法来创建一个新的 *gorm.DB
实例。因此,在第二次调用 Where
方法时,新的条件 age > 10
没有被添加到之前的条件中。
如何终结链式调用
在 GORM 中,当你调用 Finisher
方法(例如 Create
、First
、Find
、Take
、Save
、Update
、Delete
、Scan
、Row
和 Rows
等)时,它们会立即执行注册回调,然后生成并执行 SQL。这意味着,在调用 Finisher
方法之后,你不能再使用链式方法来修改查询条件。