I have the following code:
type InnerStructA struct {
A string
}
type InnerStructB struct {
B string
}
func (a *A) BeforeCreate(scope *gorm.Scope) error {
return scope.SetColumn("A", uuid.New().String())
}
func (b *B) BeforeCreate(scope *gorm.Scope) error {
return scope.SetColumn("B", uuid.New().String())
}
type OuterStruct struct {
InnerStructA
InnerStructB
ID string `gorm:"type:varchar(40);not null"`
}
When I create records:
outerStructObject := OuterStruct{
ID: "sample_ID",
}
err := db.Create(&outerStructObject).Error
only one of the BeforeCreate() hooks gets called. Other BeforeCreate gets skipped.
Gorm version is jinzhu/gorm v1.9.16
Is there a way which makes a call to both hooks when a create statement is called?
Expecting BeforeCreate hooks to be called for both inner structs - InnerStructA and InnerStructB.
Peter's comment is accurate, I'll share my tests and comments here but using the official repo at go-gorm/gorm and latest version v1.25.0
which has very similar results and some changes in the API.
When creating the Outer registry, inner objects can be set like this:
func (o *OuterStruct) BeforeCreate(tx *gorm.DB) error {
fmt.Println("Hook triggered: BeforeCreate for OuterStruct")
o.InnerStructA.A = uuid.New().String()
o.InnerStructB.B = uuid.New().String()
return nil
}
To trigger inner objects hooks, only by creating them directly:
innerA := InnerStructA{
A: "123",
}
errCreateInner := db.Create(&innerA).Error
Here is a complete isolated example:
package main
import (
"fmt"
"log"
"github.com/google/uuid"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
func main() {
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
if err != nil {
panic(err)
}
db.AutoMigrate(&InnerStructA{}, &InnerStructB{}, &OuterStruct{})
outerStructObject := OuterStruct{
ID: "sample_ID",
}
errCreate := db.Create(&outerStructObject).Error
if err != nil {
log.Fatal(errCreate)
}
var outer OuterStruct
db.Last(&outer)
fmt.Println("Last register: ", outer)
// innerA := InnerStructA{
// A: "123",
// }
// errCreateInner := db.Create(&innerA).Error
// if err != nil {
// log.Fatal(errCreateInner)
// }
}
type InnerStructA struct {
A string
}
type InnerStructB struct {
B string
}
// This is not being called
func (a *InnerStructA) BeforeCreate(tx *gorm.DB) error {
fmt.Println("Hook triggered: BeforeCreate for InnerStructA")
// ...
return nil
}
// This is not being called
func (b *InnerStructB) BeforeCreate(tx *gorm.DB) error {
fmt.Println("Hook triggered: BeforeCreate for InnerStructB")
// ...
return nil
}
// This works!
func (o *OuterStruct) BeforeCreate(tx *gorm.DB) error {
fmt.Println("Hook triggered: BeforeCreate for OuterStruct")
o.InnerStructA.A = uuid.New().String()
o.InnerStructB.B = uuid.New().String()
return nil
}
type OuterStruct struct {
InnerStructA
InnerStructB
ID string `gorm:"type:varchar(40);not null"`
}