【问题标题】:Auto Preloading with gorm not working as expected使用 gorm 自动预加载未按预期工作
【发布时间】:2018-06-15 10:44:43
【问题描述】:

我正在尝试自动预加载我的模型,但这样做有困难。

这些是我正在使用的模型:

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(...) 获取模型不会自动预加载?

【问题讨论】:

    标签: go go-gorm


    【解决方案1】:

    首先我建议阅读docs
    这里稍微解释一下。看来您很有可能使用的是旧版本。更新后的文档说明使用此标签 gorm:"PRELOAD",默认情况下设置为 true。因此,如果您想禁用某个字段,请使用 gorm:"PRELOAD:false"

    之后,必须使用db.Set("gorm:auto_preload", true) 才能正确获取。 如果您打算通过应用程序使用预加载获取,那么您可以重新分配 db 以具有 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
    

    【讨论】:

    • 如果您将在整个应用程序中使用预加载,则必须重新分配 db。该实现返回具有功能集的克隆。该功能未设置到位
    猜你喜欢
    • 1970-01-01
    • 2017-06-23
    • 1970-01-01
    • 1970-01-01
    • 2018-09-27
    • 1970-01-01
    • 2013-10-03
    • 1970-01-01
    相关资源
    最近更新 更多