2 回答
TA贡献1874条经验 获得超12个赞
使用dbConnection.Set("gorm:auto_preload", true)
,您只能加载子关系,但如果您还想加载子的子关系,则必须使用嵌套预加载。像
db.Preload("Sections").Preload("Sections.Fields").Find(&modules)
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)
}
}
- 2 回答
- 0 关注
- 145 浏览
添加回答
举报