英文:
UpdateColumns triggers Gorm hook with incorrect values
问题
我有这段代码,它更新表中的upvote
和downvote
列:
// 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 表中有 upvote
和 downvote
字段,并且在行的 upvote
/downvote
更新时自动更新 vote_score
字段。然而,如果钩子中的 upvote
和 downvote
始终为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!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论