mirror of https://github.com/go-gorm/gorm.git
Call Query callback chain when preloading many2many (#1622)
When using `Preload` on a `many2many` association, the `Query` callback chain was not being called. This made it difficult to write a plugin that could reliably get called regardless of how objects were being queried. Now `handleManyToManyPreload` will call the `Query` callback chain for each object that is retrieved by following the association. Since the data has already been read by the `handleManyToManyPreload` method, a new scope setting called `gorm:skip_queryCallback` is set to `true` before calling the callbacks. Callbacks can check for the presence of this setting if they should not be run; the default `queryCallback` is an example of this case. Fixes jinzhu/gorm#1621.
This commit is contained in:
parent
2bb1b7c83e
commit
ec72a4cb6b
|
@ -15,6 +15,10 @@ func init() {
|
|||
|
||||
// queryCallback used to query data from database
|
||||
func queryCallback(scope *Scope) {
|
||||
if _, skip := scope.Get("gorm:skip_query_callback"); skip {
|
||||
return
|
||||
}
|
||||
|
||||
defer scope.trace(NowFunc())
|
||||
|
||||
var (
|
||||
|
|
|
@ -324,6 +324,10 @@ func (scope *Scope) handleManyToManyPreload(field *Field, conditions []interface
|
|||
|
||||
scope.scan(rows, columns, append(fields, joinTableFields...))
|
||||
|
||||
scope.New(elem.Addr().Interface()).
|
||||
Set("gorm:skip_query_callback", true).
|
||||
callCallbacks(scope.db.parent.callbacks.queries)
|
||||
|
||||
var foreignKeys = make([]interface{}, len(sourceKeys))
|
||||
// generate hashed forkey keys in join table
|
||||
for idx, joinTableField := range joinTableFields {
|
||||
|
|
|
@ -1627,6 +1627,46 @@ func TestPrefixedPreloadDuplication(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPreloadManyToManyCallbacks(t *testing.T) {
|
||||
type (
|
||||
Level2 struct {
|
||||
ID uint
|
||||
}
|
||||
Level1 struct {
|
||||
ID uint
|
||||
Level2s []Level2 `gorm:"many2many:level1_level2s;AssociationForeignKey:ID;ForeignKey:ID"`
|
||||
}
|
||||
)
|
||||
|
||||
DB.DropTableIfExists("level1_level2s")
|
||||
DB.DropTableIfExists(new(Level1))
|
||||
DB.DropTableIfExists(new(Level2))
|
||||
|
||||
if err := DB.AutoMigrate(new(Level1), new(Level2)).Error; err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
lvl := Level1{
|
||||
Level2s: []Level2{
|
||||
Level2{},
|
||||
},
|
||||
}
|
||||
DB.Save(&lvl)
|
||||
|
||||
called := 0
|
||||
|
||||
DB.Callback().Query().After("gorm:query").Register("TestPreloadManyToManyCallbacks", func(scope *gorm.Scope) {
|
||||
called = called + 1
|
||||
})
|
||||
|
||||
found := Level1{ID: lvl.ID}
|
||||
DB.Preload("Level2s").First(&found, &found)
|
||||
|
||||
if called != 2 {
|
||||
t.Errorf("Wanted callback to be called 2 times but got %d", called)
|
||||
}
|
||||
}
|
||||
|
||||
func toJSONString(v interface{}) []byte {
|
||||
r, _ := json.MarshalIndent(v, "", " ")
|
||||
return r
|
||||
|
|
Loading…
Reference in New Issue