猿问

如何使用 gorm 插件/钩子将新记录插入数据库

在尝试使用 golang 中的 gorm 插入日志以检测模型的值更改时,我正在使用插件进行操作:


type MyModel struct {

 Id

 Name

}


type Log struct {

 Id

 NewValue

 OldValue

 CreatedAt

}

我的插件定义是这样的:


func ChangelogCreatePlugin(db *gorm.DB) {

    log := &Log{NewValue: "the new value", OldValue: "the old value", CreatedAt: "current time"}

    // Here is the problem

    db.Save(log) <- this is not acceptable

}

使用插件中的参数插入不同的数据模型db *gorm.DB是不可接受的,因为该参数已初始化为接受来自触发插件的同一模型的数据。


我的要求是将我的日志存储在同一个数据库事务中,因此如果其中一个失败,它们都应该失败。如何在gorm中做这样的事情?


我知道钩子。钩子在我的情况下没有用,因为我希望我的日志跟踪不同的模型,所以我正在寻找更多“可重用”的解决方案,而不是在我的模型中复制/粘贴钩子实现。


达令说
浏览 180回答 3
3回答

郎朗坤

经过大量的挖掘和调试,我想出了这个解决方案:您首先需要以正确的顺序注册您的插件执行,在我的情况下应该是这样的:gormDb.Callback().Create().Before("gorm:commit_or_rollback_transaction").Register("changelog_create", ChangelogCreatePlugin)此命令将保证您的插件将在模型的任何插入子句的事务提交之前被激活或触发。要了解有关在何处注册插件的更多信息,请查看在 gorm 中注册的默认回调这样做之后,我需要调整插件代码:func ChangelogCreatePlugin(db *gorm.DB) {&nbsp; &nbsp; // first make a check that the model insert transaction doesn't have any error&nbsp; &nbsp; if db.Error != nil {&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; log := &Log{NewValue: "the new value", OldValue: "the old value", CreatedAt: "current time"}&nbsp; &nbsp;&nbsp;&nbsp; &nbsp; // get a new db session for the new model to work&nbsp; &nbsp; logDb := db.Session(&gorm.Session{})&nbsp; &nbsp; // if an error ocurred while saving the log&nbsp; &nbsp; // push it into original model db instance errors, so it will be rolledback eventually&nbsp; &nbsp; logErr := logDb.Save(log)&nbsp; &nbsp; if logErr != nil {&nbsp; &nbsp; &nbsp; &nbsp; db.AddError(logErr)&nbsp; &nbsp; }}希望有一天这可以帮助某人!

收到一只叮咚

尝试创建事务性decorator女巫使用func(d *gorm.DB)或f ...func(d *gorm.DB)作为参数。它应该看起来像type TransactionalDecorator struct {&nbsp; &nbsp; DB *gorm.DB}func (t *TransactionalDecorator) Transaction(f ...func(d *gorm.DB) error) error&nbsp; {&nbsp; &nbsp; return t.DB.Transaction(func(tx *gorm.DB) error {&nbsp; &nbsp; &nbsp; &nbsp; for _, fn := range f {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if err := fn(tx); err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return err&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return nil&nbsp; &nbsp; })}所有数据库交互功能将在同一个事务中执行repo , _ := gorm.Open(...)tdb := &TransactionalDecorator{DB: repo}saveModel := func(d *gorm.DB) error {&nbsp; &nbsp; // save model}saveLog := func(d *gorm.DB) error {&nbsp; &nbsp; // save log}err := tdb.Transaction(saveModel, saveLog)

子衿沉夜

怎么样:func ChangelogCreatePlugin(db *gorm.DB) {&nbsp; &nbsp; log := &Log{NewValue: "the new value", OldValue: "the old value", CreatedAt: "current time"}&nbsp; &nbsp; // Here is the problem&nbsp; &nbsp; db.Session(&gorm.Session{}).Save(log)}这应该给你一个“新鲜”的 db/tx 来使用
随时随地看视频慕课网APP

相关分类

Go
我要回答