Go 扫描到具有结构映射的结构

Go 扫描到具有结构映射的结构,go,go-gorm,Go,Go Gorm,我有一个带有对象映射的结构。我希望将该映射的元素存储在一个单独的表中。我能够使用AfterFind()和BeforeSave()钩子使它在一个结构FooEntry下工作;前者在加载链接数组后调用。当加载特定行的footentrydb时,它非常有效 但是,同样的代码不适用于具有footerrydb数组的结构FooParent。问题是,当读入一行FooParent时,在添加FooEntryDb链接之前,调用AfterFind()钩子 我的查询和代码如下 查询 var pdb api.FooP

我有一个带有对象映射的结构。我希望将该映射的元素存储在一个单独的表中。我能够使用
AfterFind()
BeforeSave()钩子使它在一个结构
FooEntry
下工作;前者在加载链接数组后调用。当加载特定行的
footentrydb
时,它非常有效

但是,同样的代码不适用于具有
footerrydb
数组的结构
FooParent
。问题是,当读入一行
FooParent
时,在添加
FooEntryDb
链接之前,调用
AfterFind()
钩子

我的查询和代码如下

查询

    var pdb api.FooParentDb
    result := db.
        Joins("FooEntriesDb").
        Preload("FooEntriesDb.FooEntryLinks").
        Find(&pdb, 104185244543150166)
代码


type FooParent struct {
    FooParentPK uint64      `gorm:"primary_key;autoIncrement:false;column:foo_parent_pk;type:INT8;"`
    Entries     []*FooEntry `gorm:"-"`
}

type FooParentDb struct {
    FooParent
    FooEntriesDb []*FooEntryDb `gorm:"foreignKey:FooParentPK;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}

// TableName overrides the table name used by FooParentDb to `foo_parents`
func (FooParentDb) TableName() string {
    return "foo_parents"
}

func (tdb *FooParentDb) AfterFind(tx *gorm.DB) (err error) {
    if tx.Error == nil {
        for _, edb := range tdb.FooEntriesDb {
            edb.FooParentPK = tdb.FooParentPK
            tdb.Entries = append(tdb.Entries, &edb.FooEntry)
        }
    }
    return
}

func (tdb *FooParentDb) BeforeSave(tx *gorm.DB) (err error) {
    for _, e := range tdb.Entries {
        tdb.FooEntriesDb = append(tdb.FooEntriesDb, &FooEntryDb{FooEntry: *e, FooParentPK: tdb.FooParentPK})
    }
    return
}

// FooEntry holds one row from the foo_entries table
type FooEntry struct {
    FooEntryPK uint64           `gorm:"primary_key;autoIncrement:false;column:foo_entry_pk;type:INT8;"`
    Links      map[string]int64 `gorm:"-"`
}

// FooEntryDb holds one row from the foo_entries table
type FooEntryDb struct {
    FooEntry
    FooParentPK uint64    `gorm:"association_foreignkey:FooParentPK;column:foo_parent_pk;type:INT8;"`
    FooLinks    []FooLink `gorm:"foreignKey:EntryPK;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}

// TableName overrides the table name used by FooEntryDb to `foo_entries`
func (FooEntryDb) TableName() string {
    return "foo_entries"
}

func (edb *FooEntryDb) AfterFind(tx *gorm.DB) (err error) {
    if tx.Error == nil {
        edb.Links = make(map[string]int64)
        for _, l := range edb.FooLinks {
            if l.Key == "" {
                return fmt.Errorf("empty key for entry links")
            }
            edb.Links[l.Key] = l.Link
        }
    }
    return
}

func (edb *FooEntryDb) BeforeSave(tx *gorm.DB) (err error) {
    var sorted []string
    for key := range edb.Links {
        sorted = append(sorted, key)
    }
    sort.Slice(sorted, func(i, j int) bool { return sorted[i] < sorted[j] })
    edb.FooLinks = nil
    for _, key := range sorted {
        edb.FooLinks = append(edb.FooLinks, FooLink{Key: key, Link: edb.Links[key]})
    }
    return
}

// FooLink holds one row from the foo_entry_links table
type FooLink struct {
    FooEntryPK uint64 `gorm:"primary_key;autoIncrement:false;association_foreignkey:FooEntryPK;column:foo_entry_pk;type:INT8;"`
    Key        string `gorm:"primary_key;column:foo_key;type:VARCHAR;size:64;"`
    Link       int64  `gorm:"column:foo_link;type:INT4;"`
}

// TableName overrides the table name used by FooLink to `foo_entry_links`
func (FooLink) TableName() string {
    return "foo_entry_links"
}

类型foopparent结构{
FooParentPK uint64`gorm:“主键;自动递增:false;列:FooParentPK;类型:INT8;”`
条目[]*FooEntry`gorm:“-”`
}
类型FooParentDb struct{
食物父母
FooEntriesDb[]*FooEntryDb`gorm:“foreignKey:FooParentPK;约束:OnUpdate:CASCADE,OnDelete:SET NULL;”`
}
//TableName将FooParentDb使用的表名重写为“foo\u parents”`
func(FooParentDb)TableName()字符串{
返回“foo_父母”
}
func(tdb*FooParentDb)后发现(tx*gorm.DB)(错误){
如果发送错误==nil{
对于u,edb:=范围tdb.footeriesdb{
edb.FooParentPK=tdb.FooParentPK
Entries=append(tdb.Entries和edb.FooEntry)
}
}
返回
}
保存(tx*gorm.DB)之前的func(tdb*FooParentDb)(错误){
对于u,e:=范围tdb.条目{
tdb.foonentriesdb=append(tdb.foonentriesdb,&foonentrydb{foooentry:*e,FooParentPK:tdb.fooparentrypk})
}
返回
}
//FooEntry保存foo_entries表中的一行
类型footentry结构{
footentrypk uint64`gorm:“主键;自动递增:false;列:foo\u条目\u pk;类型:INT8;”`
链接映射[string]int64`gorm:-“`
}
//FooEntryDb保存foo_entries表中的一行
类型footentrydb struct{
食品入口
FooParentPK uint64`gorm:“关联\u外键:FooParentPK;列:FooParentPK;类型:INT8;”`
傻瓜链接[]傻瓜链接`gorm:“foreignKey:EntryPK;约束:OnUpdate:CASCADE,OnDelete:SET NULL;”`
}
//TableName将FooEntryDb使用的表名重写为“foo\u条目”`
func(FooEntryDb)TableName()字符串{
返回“foo_条目”
}
func(edb*FooEntryDb)后发现(tx*gorm.DB)(错误){
如果发送错误==nil{
edb.Links=make(映射[string]int64)
对于u,l:=范围edb{
如果l.Key==“”{
返回fmt.Errorf(“输入链接的空键”)
}
edb.Links[l.Key]=l.Link
}
}
返回
}
保存(tx*gorm.DB)之前的func(edb*FooEntryDb)(错误){
var排序的[]字符串
对于键:=范围edb.Links{
排序=追加(排序,键)
}
切片(排序,func(i,j int)bool{返回排序的[i]<排序的[j]})
edb.1=零
对于u,键:=已排序的范围{
edb.傻瓜链接=追加(edb.傻瓜链接,傻瓜链接{Key:Key,Link:edb.Links[Key]})
}
返回
}
//傻瓜链接保存foo_entry_links表中的一行
类型链接结构{
FooEntryPK uint64`gorm:“主键;自动递增:false;关联键:FooEntryPK;列:foo\u条目\u主键;类型:INT8;”`
键字符串`gorm:“主键;列:foo_键;类型:VARCHAR;大小:64;”`
Link int64`gorm:“列:foo_Link;类型:INT4;”`
}
//TableName将傻瓜链接使用的表名重写为“foo\u entry\u links”`
func(傻瓜链接)TableName()字符串{
返回“foo\u条目\u链接”
}

你能详细说明你得到的结果与你的期望不符吗?你有错误吗?其次,当你加载一个
FooEntryDb
时,它的
AfterFind
会在所有
傻瓜链接
加载后被调用?您可以发布用于加载该示例的代码吗?我可以想象的是,在使用
连接加载关系和使用
预加载
@EzequielMuns加载关系之间,
AfterFind
调用的顺序可能不一致,下面是一个工作示例。我希望考试能通过。