【问题标题】:does gorm preload not work with collection of objects?gorm 预加载不适用于对象集合吗?
【发布时间】:2020-07-09 18:33:06
【问题描述】:

我需要从 status != Complete 的 db 中获取所有模块。

我的模块表与节表有多对多映射,节表与字段表有多对多映射。

我正在尝试使用以下语句获取单个 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)

这是否意味着它仅适用于单个记录而不适用于集合?

【问题讨论】:

  • 你是如何设置模型结构的?不过,当我使用 Preload() 函数时,它对我有用。例如在您的情况下:db.Preload("Sections").Preload("Sections.Fields").Where("status != ?", enum.Completed).Find(&modules)

标签: go go-gorm


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    // 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}]}]}]
    

    通过显式预加载,您可以同时加载SectionsSections.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)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-30
      • 2017-04-23
      • 2020-06-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多