go-gorm / gorm

The fantastic ORM library for Golang, aims to be developer friendly
https://gorm.io
MIT License
36.03k stars 3.86k forks source link

Query Operation in After Update Callback Causes RowsAffected to be 0 #7044

Closed tendollor closed 15 hours ago

tendollor commented 1 month ago

I encountered an issue while using GORM for update operations. I registered an after update callback function that includes a query operation (tx.Find), but it caused the RowsAffected value of the update operation to always be 0, even though the records were successfully updated. I suspect this is a potential issue in GORM.

test code:

package main

import (
    "log"
    "reflect"

    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
)

type AAA struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

var DB *gorm.DB

func MyAfterUpdate(tx *gorm.DB) {
    if tx.Statement.Schema.ModelType == reflect.TypeOf(AAA{}) {
        var aaas []AAA
        if err := tx.Find(&aaas).Error; err != nil {
            log.Println("Failed to fetch aaas:", err)
            return
        }
        log.Println("AAA updated.")
    }
}

func main() {
    DB, _ = gorm.Open(sqlite.Open("test.db?_create=true"), &gorm.Config{})
    DB.AutoMigrate(&AAA{})
    DB.Create(&AAA{Name: "test"})

    DB.Callback().Update().After("gorm:update").Register("update_test", MyAfterUpdate) // if register this callback, result.RowsAffected will be 0

    bbb := AAA{}
    bbb.Name = "test2"
    result := DB.Model(&AAA{}).Where("name = ?", "test").Updates(bbb) // active update callback
    if result.RowsAffected > 0 {
        log.Println("Update success")
    } else {
        log.Println("Update failed")
    }
    select {}
}

I got this output

2024/06/01 17:48:32 AAA updated.
2024/06/01 17:48:32 Update failed

version info in go.mod

module test

go 1.21.9

require (
        ......
    gorm.io/driver/sqlite v1.5.5 // indirect
    gorm.io/gorm v1.25.10 // indirect
)

I want to know how to correctly retrieve the updated record information after an update operation without affecting the RowsAffected value. I need to synchronize the updated data with an in-memory table mapping. How can I achieve this?

github-actions[bot] commented 1 month ago

The issue has been automatically marked as stale as it missing playground pull request link, which is important to help others understand your issue effectively and make sure the issue hasn't been fixed on latest master, checkout https://github.com/go-gorm/playground for details. it will be closed in 30 days if no further activity occurs. if you are asking question, please use the Question template, most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.ioSearch Before Asking

ivila commented 1 month ago

@tendollor change your MyAfterUpdate method to the following, just calling Sessoin method to create a new instance, or you can try the WithContext method too:

func MyAfterUpdate(tx *gorm.DB) {
    if tx.Statement.Schema.ModelType == reflect.TypeOf(AAA{}) {
        var aaas []AAA
                // create a new session manually to avoid changes in your old tx instance,
                // and this should work with transaction too
        if err := tx.Session(&gorm.Session{}).Find(&aaas).Error; err != nil {
            log.Println("Failed to fetch aaas:", err)
            return
        }
        log.Println("AAA updated.")
    }
}
github-actions[bot] commented 1 month ago

The issue has been automatically marked as stale as it missing playground pull request link, which is important to help others understand your issue effectively and make sure the issue hasn't been fixed on latest master, checkout https://github.com/go-gorm/playground for details. it will be closed in 30 days if no further activity occurs. if you are asking question, please use the Question template, most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.ioSearch Before Asking