gorm预载不能与对象集合一起使用吗?

问题描述 投票:0回答:1

我需要从状态为!=完成的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)

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

go gorm
1个回答
0
投票

我根据您的描述编写了一个示例代码,您可以在底部找到完整的代码。让我们通过不同的选项:

// 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)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.