@@ -32,24 +32,37 @@ func SetupUpdateReflectValue(db *gorm.DB) {
3232// BeforeUpdate before update hooks
3333func BeforeUpdate (db * gorm.DB ) {
3434 if db .Error == nil && db .Statement .Schema != nil && ! db .Statement .SkipHooks && (db .Statement .Schema .BeforeSave || db .Statement .Schema .BeforeUpdate ) {
35- callMethod (db , func (value interface {}, tx * gorm.DB ) (called bool ) {
36- // save a copy before executing the hook so that can find out which fields were modified after the hook is executed.
37- rv := reflect .Indirect (reflect .ValueOf (value ))
38- rvClone := reflect .New (rv .Type ()).Elem ()
39- rvClone .Set (rv )
40-
35+ callMethod (db , func (value interface {}, tx * gorm.DB ) bool {
36+ var (
37+ beforeSaveInterface BeforeSaveInterface
38+ isBeforeSaveHook bool
39+ beforeUpdateInterface BeforeUpdateInterface
40+ isBeforeUpdateHook bool
41+ )
4142 if db .Statement .Schema .BeforeSave {
42- if i , ok := value .(BeforeSaveInterface ); ok {
43- called = true
44- db .AddError (i .BeforeSave (tx ))
45- }
43+ beforeSaveInterface , isBeforeSaveHook = value .(BeforeSaveInterface )
4644 }
47-
4845 if db .Statement .Schema .BeforeUpdate {
49- if i , ok := value .(BeforeUpdateInterface ); ok {
50- called = true
51- db .AddError (i .BeforeUpdate (tx ))
52- }
46+ beforeUpdateInterface , isBeforeUpdateHook = value .(BeforeUpdateInterface )
47+ }
48+
49+ var (
50+ called bool
51+ rv reflect.Value
52+ rvSnapshot reflect.Value
53+ )
54+ if isBeforeSaveHook || isBeforeUpdateHook {
55+ called = true
56+ // save a snapshot of the struct before the hook was called
57+ rv = reflect .Indirect (reflect .ValueOf (value ))
58+ rvSnapshot = reflect .New (rv .Type ()).Elem ()
59+ rvSnapshot .Set (rv )
60+ }
61+ if isBeforeSaveHook {
62+ db .AddError (beforeSaveInterface .BeforeSave (tx ))
63+ }
64+ if isBeforeUpdateHook {
65+ db .AddError (beforeUpdateInterface .BeforeUpdate (tx ))
5366 }
5467
5568 if called {
@@ -61,8 +74,8 @@ func BeforeUpdate(db *gorm.DB) {
6174 if ! ok {
6275 continue
6376 }
64- // compare with the copy value and update the field if there is a difference
65- if ! reflect .DeepEqual (rv .FieldByName (field .Name ).Interface (), rvClone .FieldByName (field .Name ).Interface ()) {
77+ // compare with the snapshot and update the field if there is a difference
78+ if ! reflect .DeepEqual (rv .FieldByName (field .Name ).Interface (), rvSnapshot .FieldByName (field .Name ).Interface ()) {
6679 db .Statement .SetColumn (dbFieldName , rv .FieldByName (field .Name ).Interface ())
6780 }
6881 }
0 commit comments