gorm 的自动预加载无法按预期工作
Auto Preloading with gorm not working as expected
我正在尝试自动预加载我的模型,但这样做有困难。
这些是我正在使用的模型:
package domain
type User struct {
gorm.Model
Name string
Car Car `gorm:"auto_preload"`
Account Account `gorm:"auto_preload"`
}
type Car struct {
gorm.Model
Type int
UserID uint
}
type Account struct {
gorm.Model
Powerlevel int
UserID uint
}
这是我为测试自动预加载功能而执行的代码:
func main() {
db, err := gorm.Open("sqlite3", "./data.db")
if err != nil {
println(err.Error())
}
//Migrate the tables
db.AutoMigrate(&domain.User{})
db.AutoMigrate(&domain.Car{})
db.AutoMigrate(&domain.Account{})
// Initialize our models
var testUser domain.User
var car = domain.Car{Type: 1994}
var account = domain.Account{Powerlevel: 9001}
testUser.Name = "Jim Bob"
testUser.Car = car
testUser.Account = account
// Save the user
db.Create(&testUser)
// Get a new user
var newUser domain.User
db.First(&newUser)
println(newUser.Name)
println(newUser.Car.Type)
println(newUser.Account.Powerlevel)
// Explicitly preload
db.Preload("Car").First(&newUser)
db.Preload("Account").First(&newUser)
println(newUser.Name)
println(newUser.Car.Type)
println(newUser.Account.Powerlevel)
}
两次打印的输出是:
Jim Bob
0
0
Jim Bob
1994
9001
为什么在 db.First(...) 上获取模型不会自动预加载,而我可以完全手动预加载它们?
首先,我建议阅读 docs。
这里稍微解释一下。看来您更有可能使用旧版本。更新后的文档解释了如何使用此标签 gorm:"PRELOAD"
,默认情况下该标签设置为 true。因此,如果您想禁用某个字段,请使用 gorm:"PRELOAD:false"
.
之后,使用必须使用db.Set("gorm:auto_preload", true)
才能正常获取。
如果您打算通过应用程序使用预加载提取,那么您可以重新分配数据库以具有 auto_preload 功能:
db = db.Set("gorm:auto_preload", true)
示例:
package main
import "github.com/jinzhu/gorm"
import _ "github.com/jinzhu/gorm/dialects/sqlite"
type User struct {
gorm.Model
Name string
Car Car
Account Account `gorm:"PRELOAD:false"`
}
type Car struct {
gorm.Model
Type int
UserID uint
}
type Account struct {
gorm.Model
Powerlevel int
UserID uint
}
func main() {
db, err := gorm.Open("sqlite3", "./data.db")
db.LogMode(true)
if err != nil {
println(err.Error())
}
//Migrate the tables
db.AutoMigrate(&User{})
db.AutoMigrate(&Car{})
db.AutoMigrate(&Account{})
// Initialize our models
var testUser User
var car = Car{Type: 1994}
var account = Account{Powerlevel: 9001}
testUser.Name = "Jim Bob"
testUser.Car = car
testUser.Account = account
// Save the user
db.Create(&testUser)
// Get a new user
var newUser User
// override db instance to always prefetch
//db = db.Set("gorm:auto_preload", true)
db.Set("gorm:auto_preload", true).First(&newUser)
println(newUser.Name)
println(newUser.Car.Type)
println(newUser.Account.Powerlevel)
// Explicitly preload
// No need to use two seperate statements, you can just chain them :)
db.Preload("Car").Preload("Account").First(&newUser)
//db.Preload("Account").First(&newUser)
println(newUser.Name)
println(newUser.Car.Type)
println(newUser.Account.Powerlevel)
}
输出:
(/home/william/main.go:46)
[2018-06-15 08:56:53] [0.34ms] INSERT INTO "users" ("created_at","updated_at","deleted_at","name") VALUES ('2018-06-15 08:56:53','2018-06-15 08:56:53',NULL,'Jim Bob')
[1 rows affected or returned ]
(/home/william/main.go:46)
[2018-06-15 08:56:53] [0.11ms] INSERT INTO "cars" ("created_at","updated_at","deleted_at","type","user_id") VALUES ('2018-06-15 08:56:53','2018-06-15 08:56:53',NULL,'1994','9')
[1 rows affected or returned ]
(/home/william/main.go:46)
[2018-06-15 08:56:53] [0.10ms] INSERT INTO "accounts" ("created_at","updated_at","deleted_at","powerlevel","user_id") VALUES ('2018-06-15 08:56:53','2018-06-15 08:56:53',NULL,'9001','9')
[1 rows affected or returned ]
(/home/william/main.go:51)
[2018-06-15 08:56:53] [0.69ms] SELECT * FROM "users" WHERE "users"."deleted_at" IS NULL ORDER BY "users"."id" ASC LIMIT 1
[1 rows affected or returned ]
(/home/william/main.go:51)
[2018-06-15 08:56:53] [1.93ms] SELECT * FROM "cars" WHERE "cars"."deleted_at" IS NULL AND (("user_id" IN ('1'))) ORDER BY "cars"."id" ASC
[1 rows affected or returned ]
Jim Bob
1994 <-- notice here preload is on
0 <-- notice here preload was turned off Account Type
(/home/william/main.go:59)
[2018-06-15 08:56:53] [0.28ms] SELECT * FROM "users" WHERE "users"."deleted_at" IS NULL AND "users"."id" = '1' ORDER BY "users"."id" ASC LIMIT 1
[1 rows affected or returned ]
(/home/william/main.go:59)
[2018-06-15 08:56:53] [0.33ms] SELECT * FROM "cars" WHERE "cars"."deleted_at" IS NULL AND (("user_id" IN ('1'))) ORDER BY "cars"."id" ASC
[1 rows affected or returned ]
(/home/william/main.go:60)
[2018-06-15 08:56:53] [0.27ms] SELECT * FROM "users" WHERE "users"."deleted_at" IS NULL AND "users"."id" = '1' ORDER BY "users"."id" ASC LIMIT 1
[1 rows affected or returned ]
(/home/william/main.go:60)
[2018-06-15 08:56:53] [0.46ms] SELECT * FROM "accounts" WHERE "accounts"."deleted_at" IS NULL AND (("user_id" IN ('1'))) ORDER BY "accounts"."id" ASC
[1 rows affected or returned ]
(/home/william/main.go:60)
[2018-06-15 08:56:53] [0.40ms] SELECT * FROM "cars" WHERE "cars"."deleted_at" IS NULL AND (("user_id" IN ('1'))) ORDER BY "cars"."id" ASC
[1 rows affected or returned ]
Jim Bob
1994
9001
我正在尝试自动预加载我的模型,但这样做有困难。
这些是我正在使用的模型:
package domain
type User struct {
gorm.Model
Name string
Car Car `gorm:"auto_preload"`
Account Account `gorm:"auto_preload"`
}
type Car struct {
gorm.Model
Type int
UserID uint
}
type Account struct {
gorm.Model
Powerlevel int
UserID uint
}
这是我为测试自动预加载功能而执行的代码:
func main() {
db, err := gorm.Open("sqlite3", "./data.db")
if err != nil {
println(err.Error())
}
//Migrate the tables
db.AutoMigrate(&domain.User{})
db.AutoMigrate(&domain.Car{})
db.AutoMigrate(&domain.Account{})
// Initialize our models
var testUser domain.User
var car = domain.Car{Type: 1994}
var account = domain.Account{Powerlevel: 9001}
testUser.Name = "Jim Bob"
testUser.Car = car
testUser.Account = account
// Save the user
db.Create(&testUser)
// Get a new user
var newUser domain.User
db.First(&newUser)
println(newUser.Name)
println(newUser.Car.Type)
println(newUser.Account.Powerlevel)
// Explicitly preload
db.Preload("Car").First(&newUser)
db.Preload("Account").First(&newUser)
println(newUser.Name)
println(newUser.Car.Type)
println(newUser.Account.Powerlevel)
}
两次打印的输出是:
Jim Bob
0
0
Jim Bob
1994
9001
为什么在 db.First(...) 上获取模型不会自动预加载,而我可以完全手动预加载它们?
首先,我建议阅读 docs。
这里稍微解释一下。看来您更有可能使用旧版本。更新后的文档解释了如何使用此标签 gorm:"PRELOAD"
,默认情况下该标签设置为 true。因此,如果您想禁用某个字段,请使用 gorm:"PRELOAD:false"
.
之后,使用必须使用db.Set("gorm:auto_preload", true)
才能正常获取。
如果您打算通过应用程序使用预加载提取,那么您可以重新分配数据库以具有 auto_preload 功能:
db = db.Set("gorm:auto_preload", true)
示例:
package main
import "github.com/jinzhu/gorm"
import _ "github.com/jinzhu/gorm/dialects/sqlite"
type User struct {
gorm.Model
Name string
Car Car
Account Account `gorm:"PRELOAD:false"`
}
type Car struct {
gorm.Model
Type int
UserID uint
}
type Account struct {
gorm.Model
Powerlevel int
UserID uint
}
func main() {
db, err := gorm.Open("sqlite3", "./data.db")
db.LogMode(true)
if err != nil {
println(err.Error())
}
//Migrate the tables
db.AutoMigrate(&User{})
db.AutoMigrate(&Car{})
db.AutoMigrate(&Account{})
// Initialize our models
var testUser User
var car = Car{Type: 1994}
var account = Account{Powerlevel: 9001}
testUser.Name = "Jim Bob"
testUser.Car = car
testUser.Account = account
// Save the user
db.Create(&testUser)
// Get a new user
var newUser User
// override db instance to always prefetch
//db = db.Set("gorm:auto_preload", true)
db.Set("gorm:auto_preload", true).First(&newUser)
println(newUser.Name)
println(newUser.Car.Type)
println(newUser.Account.Powerlevel)
// Explicitly preload
// No need to use two seperate statements, you can just chain them :)
db.Preload("Car").Preload("Account").First(&newUser)
//db.Preload("Account").First(&newUser)
println(newUser.Name)
println(newUser.Car.Type)
println(newUser.Account.Powerlevel)
}
输出:
(/home/william/main.go:46)
[2018-06-15 08:56:53] [0.34ms] INSERT INTO "users" ("created_at","updated_at","deleted_at","name") VALUES ('2018-06-15 08:56:53','2018-06-15 08:56:53',NULL,'Jim Bob')
[1 rows affected or returned ]
(/home/william/main.go:46)
[2018-06-15 08:56:53] [0.11ms] INSERT INTO "cars" ("created_at","updated_at","deleted_at","type","user_id") VALUES ('2018-06-15 08:56:53','2018-06-15 08:56:53',NULL,'1994','9')
[1 rows affected or returned ]
(/home/william/main.go:46)
[2018-06-15 08:56:53] [0.10ms] INSERT INTO "accounts" ("created_at","updated_at","deleted_at","powerlevel","user_id") VALUES ('2018-06-15 08:56:53','2018-06-15 08:56:53',NULL,'9001','9')
[1 rows affected or returned ]
(/home/william/main.go:51)
[2018-06-15 08:56:53] [0.69ms] SELECT * FROM "users" WHERE "users"."deleted_at" IS NULL ORDER BY "users"."id" ASC LIMIT 1
[1 rows affected or returned ]
(/home/william/main.go:51)
[2018-06-15 08:56:53] [1.93ms] SELECT * FROM "cars" WHERE "cars"."deleted_at" IS NULL AND (("user_id" IN ('1'))) ORDER BY "cars"."id" ASC
[1 rows affected or returned ]
Jim Bob
1994 <-- notice here preload is on
0 <-- notice here preload was turned off Account Type
(/home/william/main.go:59)
[2018-06-15 08:56:53] [0.28ms] SELECT * FROM "users" WHERE "users"."deleted_at" IS NULL AND "users"."id" = '1' ORDER BY "users"."id" ASC LIMIT 1
[1 rows affected or returned ]
(/home/william/main.go:59)
[2018-06-15 08:56:53] [0.33ms] SELECT * FROM "cars" WHERE "cars"."deleted_at" IS NULL AND (("user_id" IN ('1'))) ORDER BY "cars"."id" ASC
[1 rows affected or returned ]
(/home/william/main.go:60)
[2018-06-15 08:56:53] [0.27ms] SELECT * FROM "users" WHERE "users"."deleted_at" IS NULL AND "users"."id" = '1' ORDER BY "users"."id" ASC LIMIT 1
[1 rows affected or returned ]
(/home/william/main.go:60)
[2018-06-15 08:56:53] [0.46ms] SELECT * FROM "accounts" WHERE "accounts"."deleted_at" IS NULL AND (("user_id" IN ('1'))) ORDER BY "accounts"."id" ASC
[1 rows affected or returned ]
(/home/william/main.go:60)
[2018-06-15 08:56:53] [0.40ms] SELECT * FROM "cars" WHERE "cars"."deleted_at" IS NULL AND (("user_id" IN ('1'))) ORDER BY "cars"."id" ASC
[1 rows affected or returned ]
Jim Bob
1994
9001