为了账号安全,请及时绑定邮箱和手机立即绑定

gorm 预加载不适用于对象集合吗?

gorm 预加载不适用于对象集合吗?

Go
慕妹3242003 2022-05-23 16:50:29
我需要从 db where 获取所有模块status != Complete。我的模块表与节表具有多对多映射,节表与字段表具有多对多映射。我正在尝试使用下面的语句获取单个 DB 查询中的所有模块。dbConnection.Set("gorm:auto_preload", true).Where("status != ?", enum.Completed).Find(&modules)但它不返回部分和字段。如果我使用下面的语句,那么它会返回嵌套模型。dbConnection.Set("gorm:auto_preload", true).Where("status != ?", enum.Completed).First(&modules)这是否意味着它仅适用于单个记录而不适用于集合?
查看完整描述

2 回答

?
HUWWW

TA贡献1874条经验 获得超12个赞

使用dbConnection.Set("gorm:auto_preload", true),您只能加载子关系,但如果您还想加载子的子关系,则必须使用嵌套预加载。像

db.Preload("Sections").Preload("Sections.Fields").Find(&modules)


查看完整回答
反对 回复 2022-05-23
?
守着星空守着你

TA贡献1799条经验 获得超8个赞

我根据你的描述写了一个示例代码,你可以在底部找到完整的代码。让我们来看看不同的选择:


// Use auto_preload and .First

db.Set("gorm:auto_preload", true).Where("name = ?", "m0").First(&modules)


Output:

[{ID:1 Name:m0 Status:0 Sections:[{ID:2 Name:s1 Fields:[]}]}]

因此,.First您可以得到部分,但不能得到Sections.Fields


// Use auto_preload and .Find

db.Set("gorm:auto_preload", true).Find(&modules)


Output:

[{ID:1 Name:m0 Status:0 Sections:[{ID:2 Name:s1 Fields:[]}]} {ID:2 Name:m1 Status:0 Sections:[{ID:1 Name:s0 Fields:[]}]}]

与.Find您获得相同的行为.First


// Use .Preload

db.Preload("Sections").Preload("Sections.Fields").Find(&modules)


Output:

[{ID:1 Name:m0 Status:0 Sections:[{ID:2 Name:s1 Fields:[{ID:1 Name:f0} {ID:2 Name:f1}]}]} {ID:2 Name:m1 Status:0 Sections:[{ID:1 Name:s0 Fields:[{ID:1 Name:f0} {ID:3 Name:f2}]}]}]

通过显式预加载,您可以同时加载Sections和Sections.Fields。仅使用auto_preload预加载直接字段,而不是更深的字段。IMO 使用显式预加载通常是一种更好的做法。


完整代码:


package main


import (

    "fmt"

    "github.com/jinzhu/gorm"

    _ "github.com/jinzhu/gorm/dialects/sqlite"

    "log"

)


type Module struct {

    ID       int `gorm:"primary_key"`

    Name     string

    Status   int

    Sections []Section `gorm:"many2many:module_sections;"`

}


type Section struct {

    ID     int `gorm:"primary_key"`

    Name   string

    Fields []Field `gorm:"many2many:section_fields;"`

}


type Field struct {

    ID   int `gorm:"primary_key"`

    Name string

}


func preloadingSample() error {

    db, err := gorm.Open("sqlite3", "test.db")

    if err != nil {

        return fmt.Errorf("open DB failed: %w", err)

    }

    defer db.Close()


    err = db.AutoMigrate(

        &Module{},

        &Section{},

        &Field{},

    ).Error

    if err != nil {

        return fmt.Errorf("migration failed: %w", err)

    }


    // Delete everything in DB

    db.Delete(&Module{})

    db.Delete(&Section{})

    db.Delete(&Field{})


    // Put some sample data in DB

    sampleFields := []Field{

        {Name: "f0"},

        {Name: "f1"},

        {Name: "f2"},

        {Name: "f3"},

    }

    for idx := range sampleFields {

        err = db.Create(&sampleFields[idx]).Error

        if err != nil {

            return fmt.Errorf("failed to create: %w", err)

        }

    }


    sampleSections := []Section{

        {Name: "s0", Fields: []Field{sampleFields[0], sampleFields[2]}},

        {Name: "s1", Fields: []Field{sampleFields[0], sampleFields[1]}},

    }

    for idx := range sampleSections {

        err = db.Create(&sampleSections[idx]).Error

        if err != nil {

            return fmt.Errorf("failed to create: %w", err)

        }

    }


    sampleModules := []Module{

        {Name: "m0", Sections: []Section{sampleSections[1]}},

        {Name: "m1", Sections: []Section{sampleSections[0]}},

    }

    for idx := range sampleModules {

        err = db.Create(&sampleModules[idx]).Error

        if err != nil {

            return fmt.Errorf("failed to create: %w", err)

        }

    }


    var modules []Module


    // Load just one module with auto_preload

    err = db.Set("gorm:auto_preload", true).Where("name = ?", "m0").First(&modules).Error

    if err != nil {

        return fmt.Errorf("auto_preload first: %w", err)

    }

    fmt.Printf("%+v\n", modules)


    // Load all modules with auto_preload

    err = db.Set("gorm:auto_preload", true).Find(&modules).Error

    if err != nil {

        return fmt.Errorf("auto_preload find: %w", err)

    }

    fmt.Printf("%+v\n", modules)


    // Explicitly load

    err = db.Preload("Sections").Preload("Sections.Fields").Find(&modules).Error

    if err != nil {

        return fmt.Errorf("preload find: %w", err)

    }

    fmt.Printf("%+v\n", modules)


    return nil

}


func main() {

    err := preloadingSample()

    if err != nil {

        log.Fatal(err)

    }

}



查看完整回答
反对 回复 2022-05-23
  • 2 回答
  • 0 关注
  • 145 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信