How to save a map[] as relation with GORM?
There is no way to do this out of the box with Gorm, but you could try to implement something like this with some hooks.
The strategy would be to represent the HasMany relationship as is standard, and then keep some unexported (thus hidden to Gorm) field which is the map:
type A struct {
gorm.Model
Bs []*B
bsAsMap map[uint]*B
}
type B struct {
gorm.Model
AID uint
SomeValue string
}
Note the lowercase b in bsAsMany
means the field is unexported, so invisible to gorm. I used uint type keys as that's what gorm.Model uses. AID is the ID of A that has this B.
The AfterFind
hook gets run after any operation that queries the entity from the database.
func (a *A) AfterFind(tx *gorm.DB) error {
a.bsAsMap = make(map[uint]*B, len(a.Bs))
for _, b := range a.Bs {
a.bsAsMap[b.ID] = b
}
return nil
}
You'll also want to use a BeforeSave
hook in order to save any changes in the bsAsMap
field to the Bs
slice:
func (a *A) BeforeSave(tx *gorm.DB) error {
a.Bs = make([]*B, 0, len(a.bsAsMap))
for _, b := range a.bsAsMap {
a.Bs = append(a.Bs, b)
}
return nil
}
This means that bsAsMap
becomes the source of truth for the relationship from the point of view of your app code and any changes to Bs
will be undone on save. Because bsAsMap
is an unexported field, you won't be able to access it in other packages, but you can overcome that by adding accessor methods like GetB(id uint) *B
and SetB(*B)
.