forked from mirror/gorm
Transaction in callbacks
This commit is contained in:
parent
96ade8c619
commit
31c64a9c95
52
README.md
52
README.md
|
@ -598,16 +598,43 @@ db.Select("name, age").Find(&users)
|
||||||
## Callbacks
|
## Callbacks
|
||||||
|
|
||||||
Callbacks are functions defined to struct's pointer, they would be run when save a struct to database.
|
Callbacks are functions defined to struct's pointer, they would be run when save a struct to database.
|
||||||
If any callback return error, gorm will stop future operations and do rollback
|
If any callback return error, gorm will stop future operations and rollback all changes
|
||||||
|
|
||||||
Below callbacks are supported now:
|
Here is a list with all available callbacks,
|
||||||
|
listed in the same order in which they will get called during the respective operations.
|
||||||
|
|
||||||
`BeforeCreate`, `AfterCreate`
|
### Creating an Object
|
||||||
`BeforeUpdate`, `AfterUpdate`
|
|
||||||
`BeforeSave`, `AfterSave`
|
|
||||||
`BeforeDelete`, `AfterDelete`
|
|
||||||
|
|
||||||
For example:
|
```go
|
||||||
|
BeforeSave
|
||||||
|
BeforeCreate
|
||||||
|
// save before associations
|
||||||
|
// save self
|
||||||
|
// save after associations
|
||||||
|
AfterCreate
|
||||||
|
AfterSave
|
||||||
|
```
|
||||||
|
### Updating an Object
|
||||||
|
|
||||||
|
```go
|
||||||
|
BeforeSave
|
||||||
|
BeforeUpdate
|
||||||
|
// save before associations
|
||||||
|
// save self
|
||||||
|
// save after associations
|
||||||
|
AfterUpdate
|
||||||
|
AfterSave
|
||||||
|
```
|
||||||
|
|
||||||
|
### Destroying an Object
|
||||||
|
|
||||||
|
```go
|
||||||
|
BeforeDelete
|
||||||
|
// delete self
|
||||||
|
AfterDelete
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is an example:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
func (u *User) BeforeUpdate() (err error) {
|
func (u *User) BeforeUpdate() (err error) {
|
||||||
|
@ -626,6 +653,17 @@ func (u *User) AfterCreate() (err error) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```go
|
||||||
|
// As you know, the save/delete operations are running in a transaction
|
||||||
|
// This is means all your changes will be rollbacked if get any errors
|
||||||
|
// If you want your changes in callbacks be run in the same transaction
|
||||||
|
// You have to pass the transaction as argument to the function
|
||||||
|
func (u *User) AfterCreate(tx *gorm.DB) (err error) {
|
||||||
|
tx.Model(u).Update("role", "admin")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Specify Table Name
|
## Specify Table Name
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
|
4
do.go
4
do.go
|
@ -173,8 +173,8 @@ func (s *Do) saveAfterAssociations() {
|
||||||
|
|
||||||
func (s *Do) create() (i interface{}) {
|
func (s *Do) create() (i interface{}) {
|
||||||
defer s.trace(time.Now())
|
defer s.trace(time.Now())
|
||||||
s.model.callMethod("BeforeCreate")
|
|
||||||
s.model.callMethod("BeforeSave")
|
s.model.callMethod("BeforeSave")
|
||||||
|
s.model.callMethod("BeforeCreate")
|
||||||
|
|
||||||
s.saveBeforeAssociations()
|
s.saveBeforeAssociations()
|
||||||
s.prepareCreateSql()
|
s.prepareCreateSql()
|
||||||
|
@ -274,8 +274,8 @@ func (s *Do) update() *Do {
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
s.model.callMethod("BeforeUpdate")
|
|
||||||
s.model.callMethod("BeforeSave")
|
s.model.callMethod("BeforeSave")
|
||||||
|
s.model.callMethod("BeforeUpdate")
|
||||||
s.saveBeforeAssociations()
|
s.saveBeforeAssociations()
|
||||||
|
|
||||||
s.prepareUpdateSql(true)
|
s.prepareUpdateSql(true)
|
||||||
|
|
12
gorm_test.go
12
gorm_test.go
|
@ -588,8 +588,8 @@ func (s *Product) BeforeSave() (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Product) AfterCreate() {
|
func (s *Product) AfterCreate(db *DB) {
|
||||||
s.AfterCreateCallTimes = s.AfterCreateCallTimes + 1
|
db.Model(s).UpdateColumn(Product{AfterCreateCallTimes: s.AfterCreateCallTimes + 1})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Product) AfterUpdate() {
|
func (s *Product) AfterUpdate() {
|
||||||
|
@ -633,23 +633,23 @@ func TestRunCallbacks(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
db.Where("Code = ?", "unique_code").First(&p)
|
db.Where("Code = ?", "unique_code").First(&p)
|
||||||
if !reflect.DeepEqual(p.GetCallTimes(), []int64{1, 1, 0, 0, 0, 0, 0, 0}) {
|
if !reflect.DeepEqual(p.GetCallTimes(), []int64{1, 1, 0, 1, 0, 0, 0, 0}) {
|
||||||
t.Errorf("After callbacks values are not saved, %v", p.GetCallTimes())
|
t.Errorf("After callbacks values are not saved, %v", p.GetCallTimes())
|
||||||
}
|
}
|
||||||
|
|
||||||
p.Price = 200
|
p.Price = 200
|
||||||
db.Save(&p)
|
db.Save(&p)
|
||||||
if !reflect.DeepEqual(p.GetCallTimes(), []int64{1, 2, 1, 0, 1, 1, 0, 0}) {
|
if !reflect.DeepEqual(p.GetCallTimes(), []int64{1, 2, 1, 1, 1, 1, 0, 0}) {
|
||||||
t.Errorf("After update callbacks should be invoked successfully, %v", p.GetCallTimes())
|
t.Errorf("After update callbacks should be invoked successfully, %v", p.GetCallTimes())
|
||||||
}
|
}
|
||||||
|
|
||||||
db.Where("Code = ?", "unique_code").First(&p)
|
db.Where("Code = ?", "unique_code").First(&p)
|
||||||
if !reflect.DeepEqual(p.GetCallTimes(), []int64{1, 2, 1, 0, 0, 0, 0, 0}) {
|
if !reflect.DeepEqual(p.GetCallTimes(), []int64{1, 2, 1, 1, 0, 0, 0, 0}) {
|
||||||
t.Errorf("After update callbacks values are not saved, %v", p.GetCallTimes())
|
t.Errorf("After update callbacks values are not saved, %v", p.GetCallTimes())
|
||||||
}
|
}
|
||||||
|
|
||||||
db.Delete(&p)
|
db.Delete(&p)
|
||||||
if !reflect.DeepEqual(p.GetCallTimes(), []int64{1, 2, 1, 0, 0, 0, 1, 1}) {
|
if !reflect.DeepEqual(p.GetCallTimes(), []int64{1, 2, 1, 1, 0, 0, 1, 1}) {
|
||||||
t.Errorf("After delete callbacks should be invoked successfully, %v", p.GetCallTimes())
|
t.Errorf("After delete callbacks should be invoked successfully, %v", p.GetCallTimes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
model.go
11
model.go
|
@ -239,8 +239,15 @@ func (m *Model) callMethod(method string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if fm := reflect.ValueOf(m.data).MethodByName(method); fm.IsValid() {
|
if fm := reflect.ValueOf(m.data).MethodByName(method); fm.IsValid() {
|
||||||
if v := fm.Call([]reflect.Value{}); len(v) > 0 {
|
numin := fm.Type().NumIn()
|
||||||
if verr, ok := v[0].Interface().(error); ok {
|
var results []reflect.Value
|
||||||
|
if numin == 0 {
|
||||||
|
results = fm.Call([]reflect.Value{})
|
||||||
|
} else if numin == 1 {
|
||||||
|
results = fm.Call([]reflect.Value{reflect.ValueOf(m.do.db.new())})
|
||||||
|
}
|
||||||
|
if len(results) > 0 {
|
||||||
|
if verr, ok := results[0].Interface().(error); ok {
|
||||||
m.do.err(verr)
|
m.do.err(verr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,12 @@ func (s *DB) clone() *DB {
|
||||||
return &db
|
return &db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DB) new() *DB {
|
||||||
|
db := DB{db: s.db, parent: s.parent, logMode: s.logMode, data: s.data, Error: s.Error, search: &search{}}
|
||||||
|
db.search.db = &db
|
||||||
|
return &db
|
||||||
|
}
|
||||||
|
|
||||||
func (s *DB) do(data interface{}) *Do {
|
func (s *DB) do(data interface{}) *Do {
|
||||||
s.data = data
|
s.data = data
|
||||||
do := Do{db: s}
|
do := Do{db: s}
|
||||||
|
|
Loading…
Reference in New Issue