更新列触发 Gorm 钩子时,传递的值不正确。

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

UpdateColumns triggers Gorm hook with incorrect values

问题

我有这段代码,它更新表中的upvotedownvote列:

// tx 是我的事务

// `content.model` 是一个模型接口

// `content.id` 是我要更新的内容的ID

// `columnUpdates` 是一个 `columnUpdates := make(map[string]interface{})`,其中包含对 upvote 和 downvote 列的多个不同更新

...

query := tx.Model(content.model).
	Where("id = ?", content.id).
	UpdateColumns(columnUpdates)
if err := query.Error; err != nil {
	tx.Rollback()
	return err
}

...这会触发以下 Gorm 钩子(已验证,它确实触发):

func (p *Post) AfterUpdate(tx *gorm.DB) error {
	fmt.Println("upvotes: ", p.Upvote)
	fmt.Println("downvotes: ", p.Downvote)
	p.VoteScore = int(p.Upvote) - int(p.Downvote)
	return nil
}

但是,无论它们的值是否为0,该钩子始终打印出两个投票的值为0。

我的目标是在我的 PostgreSQL 表中有 upvotedownvote 字段,并且在行的 upvote/downvote 更新时自动更新 vote_score 字段。然而,如果钩子中的 upvotedownvote 始终为0,那么 vote_score 将无法正确计算。

如何在 Gorm 钩子中获取正确的投票值?

这是我的 Post 结构模型,只显示了相关字段:

type Post struct {
	Downvote      uint         `gorm:"column:downvote"`
	Upvote        uint         `gorm:"column:upvote"`
	VoteScore     int          `gorm:"column:vote_score"`
}

谢谢。

英文:

I have this code which updates the upvote and downvote columns in my table:

// tx is my transaction

// `content.model` is a model interface

// `content.id` is the ID of what I'm going for

// `columnUpdates` is a `columnUpdates := make(map[string]interface{})` with 
// a bunch of different updates to the upvote & downvote columns

...

query := tx.Model(content.model).
	Where("id = ?", content.id).
	UpdateColumns(columnUpdates)
if err := query.Error; err != nil {
	tx.Rollback()
	return err
}

...which in turn triggers this Gorm hook (checked, it does trigger it):

func (p *Post) AfterUpdate(tx *gorm.DB) error {
	fmt.Println("upvotes: ", p.Upvote)
	fmt.Println("downvotes: ", p.Downvote)
	p.VoteScore = int(p.Upvote) - int(p.Downvote)
	return nil
}

but the hook always prints both votes as 0 even though they are not 0.

My goal is to have upvote and downvote fields inside my postgres table and a vote_score field that is auto-updated upon a row's upvote/downvote being updated. However, vote_score won't be calculated properly if upvote and downvote are always 0 in the hook.

How can I get the correct vote values in the Gorm Hook?

Here is my Post struct model, with just the relevant fields shown:

type Post struct {
	Downvote      uint         `gorm:"column:downvote"`
	Upvote        uint         `gorm:"column:upvote"`
	VoteScore     int          `gorm:"column:vote_score"`
}

Thanks.

答案1

得分: 1

我刚刚查看了你的代码,并发现了一些问题。首先,让我展示一下我的工作代码,然后我会逐步向你介绍更改的内容。

package main

import (
	"fmt"

	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

type Post struct {
	ID        int
	Downvote  uint `gorm:"column:downvote"`
	Upvote    uint `gorm:"column:upvote"`
	VoteScore int  `gorm:"column:vote_score"`
}

func (p *Post) AfterUpdate(tx *gorm.DB) error {
	fmt.Println("upvotes: ", p.Upvote)
	fmt.Println("downvotes: ", p.Downvote)
	p.VoteScore = int(p.Upvote) - int(p.Downvote)
	if err := tx.Model(&Post{}).Where("id = ?", p.ID).UpdateColumn("vote_score", p.VoteScore).Error; err != nil {
		return err
	}
	return nil
}

func main() {
	dsn := "host=localhost port=54322 user=postgres password=postgres dbname=postgres sslmode=disable"
	db, err := gorm.Open(postgres.Open(dsn))
	if err != nil {
		panic(err)
	}
	db.AutoMigrate(&Post{})

	// db.Create(&Post{ID: 1})

	if err := db.Model(&Post{ID: 1}).Where("id = ?", 1).Updates(map[string]interface{}{"upvote": 4, "downvote": 3}).Error; err != nil {
		db.Rollback()
		fmt.Println(err.Error())
		return
	}
}

第一个问题是使用了UpdateColumns方法。后者只在你不希望触发时间跟踪和钩子时使用。你可以在GORM文档的这一部分找到更多信息:链接

在将ID添加到结构体后,我确保在AfterUpdate钩子中设置了正确的ID。通过这样做,你可以重新运行更新操作来编辑刚刚更新的记录。

如果你不想运行两次更新操作,你可以使用另一个在更新之前运行的钩子。

如果这解决了你的问题,请告诉我,谢谢!

英文:

I've just looked at your code and I found out a couple of issues. First, let me present my working code, then, I'm gonna walk you through the changes.

package main

import (
	"fmt"

	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

type Post struct {
	ID        int
	Downvote  uint `gorm:"column:downvote"`
	Upvote    uint `gorm:"column:upvote"`
	VoteScore int  `gorm:"column:vote_score"`
}

func (p *Post) AfterUpdate(tx *gorm.DB) error {
	fmt.Println("upvotes: ", p.Upvote)
	fmt.Println("downvotes: ", p.Downvote)
	p.VoteScore = int(p.Upvote) - int(p.Downvote)
	if err := tx.Model(&Post{}).Where("id = ?", p.ID).UpdateColumn("vote_score", p.VoteScore).Error; err != nil {
		return err
	}
	return nil
}

func main() {
	dsn := "host=localhost port=54322 user=postgres password=postgres dbname=postgres sslmode=disable"
	db, err := gorm.Open(postgres.Open(dsn))
	if err != nil {
		panic(err)
	}
	db.AutoMigrate(&Post{})

	// db.Create(&Post{ID: 1})

	if err := db.Model(&Post{ID: 1}).Where("id = ?", 1).Updates(map[string]interface{}{"upvote": 4, "downvote": 3}).Error; err != nil {
		db.Rollback()
		fmt.Println(err.Error())
		return
	}
}

The first issue is the usage of the method UpdateColumns. The latter must be used when you want neither the time tracking nor the hooks to be triggered. You can find more in this section of the GORM documentation: link.
After adding the ID to the struct, I make sure that the correct ID was set in the AfterUpdate hook. Thanks to this you can re-run an update to edit the just updated record.

If you don't want to run two updates you might use another hook that runs before the update.

Let me know if this solves your issue, thanks!

huangapple
  • 本文由 发表于 2023年6月9日 12:27:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/76437210.html
匿名

发表评论

匿名网友

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

确定