I have the following contrived example:
type Top struct {
ID uint `gorm:"primary_key"`
Name string
Middle []*Middle
}
type Middle struct {
ID uint `gorm:"primary_key"`
TopID int
Name string
Low []*Low
}
type Low struct {
ID uint `gorm:"primary_key"`
MiddleID int
Name string
Bottom []*Bottom
}
type Bottom struct {
ID uint `gorm:"primary_key"`
LowID int
Name string
}
top := Top{
Name: "Top",
Middle: []*Middle{
{
Name: "Middle",
Low: []*Low{
{
Name: "Low",
Bottom: []*Bottom{
{
Name: "Bottom",
},
},
},
},
},
},
}
if err := db.Save(&top).Error; err != nil {
log.Fatal("Got errors when saving calc", err.Error())
}
if err := db.Where("id = 1").
Preload("Middle.Low.Bottom").
First(&top).Error; err != nil {
log.Fatal(err)
}
This gives me the following output:
(/host_home/workspace/golang/src/bitbucket.org/cloudgloballog/gormtest/main.go:81)
[2016-03-18 01:53:23] [4.37ms] INSERT INTO "tops" ("name") VALUES ('Top') RETURNING "tops"."id"
(/host_home/workspace/golang/src/bitbucket.org/cloudgloballog/gormtest/main.go:81)
[2016-03-18 01:53:23] [3.49ms] INSERT INTO "middles" ("name","top_id") VALUES ('Middle','1') RETURNING "middles"."id"
(/host_home/workspace/golang/src/bitbucket.org/cloudgloballog/gormtest/main.go:81)
[2016-03-18 01:53:23] [1.07ms] INSERT INTO "lows" ("middle_id","name") VALUES ('1','Low') RETURNING "lows"."id"
()
[2016-03-18 01:53:23] [9.16ms] INSERT INTO "bottoms" ("low_id","name") VALUES ('1','Bottom') RETURNING "bottoms"."id"
(/host_home/workspace/golang/src/bitbucket.org/cloudgloballog/gormtest/main.go:86)
[2016-03-18 01:53:23] [1.54ms] SELECT * FROM "tops" ORDER BY "tops"."id" ASC LIMIT 1
(/host_home/workspace/golang/src/bitbucket.org/cloudgloballog/gormtest/main.go:88)
[2016-03-18 01:53:23] [2.63ms] SELECT * FROM "tops" WHERE ("id" = '1') ORDER BY "tops"."id" ASC LIMIT 1
(/host_home/workspace/golang/src/bitbucket.org/cloudgloballog/gormtest/main.go:88)
[2016-03-18 01:53:23] [1.65ms] SELECT * FROM "middles" WHERE (top_id IN ('1')) ORDER BY "middles"."id" ASC
(/host_home/workspace/golang/src/bitbucket.org/cloudgloballog/gormtest/main.go:88)
[2016-03-18 01:53:23] [4.20ms] SELECT * FROM "lows" WHERE (middle_id IN ('1')) ORDER BY "lows"."id" ASC
(/host_home/workspace/golang/src/bitbucket.org/cloudgloballog/gormtest/main.go:88)
[2016-03-18 01:53:23] can't find field Bottom in []**main.Low
If I were to only nest Top -> Middle -> Low and called Preload("Middle.Low")
it works fine. The clue is probably in the double pointer reference []**main.Low
but I'm unable to work out how to do this properly.
It's possible that nested preloading is not supported to this level. Anyone know?
This issue seems to have been present in earlier versions of gorm as described in: Issue1, Issue2, Issue3, but the lastest preload issue fix has been in this one.
It appears it has been resolved for quite some time but the exact version it was fixed is not documented unless someone searches git commit dates.
Setting up a current example with the latest version (v1.9.11 as of this writing) held no issues.
package main
import (
"log"
"github.com/davecgh/go-spew/spew"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
)
type Top struct {
ID uint `gorm:"primary_key"`
Name string
Middle []*Middle
}
type Middle struct {
ID uint `gorm:"primary_key"`
TopID int
Name string
Low []*Low
}
type Low struct {
ID uint `gorm:"primary_key"`
MiddleID int
Name string
Bottom []*Bottom
}
type Bottom struct {
ID uint `gorm:"primary_key"`
LowID int
Name string
}
func main() {
db, err := gorm.Open("sqlite3", "test.db")
if err != nil {
panic("failed to connect database")
}
defer db.Close()
// Enable Logger, show detailed log
db.LogMode(true)
// Migrate the schema
db.AutoMigrate(&Top{})
db.AutoMigrate(&Middle{})
db.AutoMigrate(&Low{})
db.AutoMigrate(&Bottom{})
top := Top{
Name: "Top",
Middle: []*Middle{
{
Name: "Middle",
Low: []*Low{
{
Name: "Low",
Bottom: []*Bottom{
{
Name: "Bottom",
},
},
},
},
},
},
}
if err := db.Save(&top).Error; err != nil {
log.Fatal("Got errors when saving calc", err.Error())
}
var ntop Top
if err := db.Where("id = 1").
Preload("Middle.Low.Bottom").
First(&ntop).Error; err != nil {
log.Fatal(err)
}
spew.Dump(&ntop)
}
$ ./main.exe
(C:/Users/fakename/source/stackoverflow/go/gorm-nested/main.go:70)
[2019-10-31 14:44:23] [2.00ms] INSERT INTO "tops" ("name") VALUES ('Top')
[1 rows affected or returned ]
(C:/Users/fakename/source/stackoverflow/go/gorm-nested/main.go:70)
[2019-10-31 14:44:23] [0.00ms] INSERT INTO "middles" ("top_id","name") VALUES (1,'Middle')
[1 rows affected or returned ]
(C:/Users/fakename/source/stackoverflow/go/gorm-nested/main.go:70)
[2019-10-31 14:44:23] [0.99ms] INSERT INTO "lows" ("middle_id","name") VALUES (1,'Low')
[1 rows affected or returned ]
()
[2019-10-31 14:44:23] [0.00ms] INSERT INTO "bottoms" ("low_id","name") VALUES (1,'Bottom')
[1 rows affected or returned ]
(C:/Users/fakename/source/stackoverflow/go/gorm-nested/main.go:76)
[2019-10-31 14:44:23] [0.00ms] SELECT * FROM "tops" WHERE (id = 1) ORDER BY "tops"."id" ASC LIMIT 1
[1 rows affected or returned ]
(C:/Users/fakename/source/stackoverflow/go/gorm-nested/main.go:76)
[2019-10-31 14:44:23] [0.00ms] SELECT * FROM "middles" WHERE ("top_id" IN (1)) ORDER BY "middles"."id" ASC
[1 rows affected or returned ]
(C:/Users/fakename/source/stackoverflow/go/gorm-nested/main.go:76)
[2019-10-31 14:44:23] [0.00ms] SELECT * FROM "lows" WHERE ("middle_id" IN (1)) ORDER BY "lows"."id" ASC
[1 rows affected or returned ]
(C:/Users/fakename/source/stackoverflow/go/gorm-nested/main.go:76)
[2019-10-31 14:44:23] [0.99ms] SELECT * FROM "bottoms" WHERE ("low_id" IN (1)) ORDER BY "bottoms"."id" ASC
[1 rows affected or returned ]
(*main.Top)(0xc00015f950)({
ID: (uint) 1,
Name: (string) (len=3) "Top",
Middle: ([]*main.Middle) (len=1 cap=1) {
(*main.Middle)(0xc000150fc0)({
ID: (uint) 1,
TopID: (int) 1,
Name: (string) (len=6) "Middle",
Low: ([]*main.Low) (len=1 cap=1) {
(*main.Low)(0xc000151080)({
ID: (uint) 1,
MiddleID: (int) 1,
Name: (string) (len=3) "Low",
Bottom: ([]*main.Bottom) (len=1 cap=1) {
(*main.Bottom)(0xc0001929c0)({
ID: (uint) 1,
LowID: (int) 1,
Name: (string) (len=6) "Bottom"
})
}
})
}
})
}
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With