@@ -32,24 +32,37 @@ func SetupUpdateReflectValue(db *gorm.DB) {
32
32
// BeforeUpdate before update hooks
33
33
func BeforeUpdate (db * gorm.DB ) {
34
34
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
+ )
41
42
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 )
46
44
}
47
-
48
45
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 ))
53
66
}
54
67
55
68
if called {
@@ -61,8 +74,8 @@ func BeforeUpdate(db *gorm.DB) {
61
74
if ! ok {
62
75
continue
63
76
}
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 ()) {
66
79
db .Statement .SetColumn (dbFieldName , rv .FieldByName (field .Name ).Interface ())
67
80
}
68
81
}
0 commit comments