有没有办法为结构体中的每个结构体执行BeforeCreate和BeforeUpdate钩子函数?

huangapple go评论99阅读模式
英文:

Is there a way to execute BeforeCreate and BeforeUpdate hooks for every struct inside a struct?

问题

我有以下代码:

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"`
}

当我创建记录时:

outerStructObject := OuterStruct{
		ID:          "sample_ID",
}
err := db.Create(&outerStructObject).Error

只有一个 BeforeCreate() 钩子被调用。其他 BeforeCreate 被跳过。

Gorm 版本是 jinzhu/gorm v1.9.16

是否有一种方法可以在调用创建语句时同时调用两个钩子?

期望在 InnerStructA 和 InnerStructB 的结构体上都调用 BeforeCreate 钩子。

英文:

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.

答案1

得分: 1

Peter的评论是准确的,我将在这里分享我的测试和评论,但是使用官方仓库go-gorm/gorm和最新版本v1.25.0,该版本具有非常相似的结果和一些API的更改。

在创建Outer registry时,可以像这样设置内部对象:

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
}

要触发内部对象的钩子,只需直接创建它们:

innerA := InnerStructA{
	A: "123",
}

errCreateInner := db.Create(&innerA).Error

这是一个完整的独立示例:

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"`
}
英文:

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"`
}

huangapple
  • 本文由 发表于 2023年5月3日 22:27:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76165008.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定