Fixed bug when preload duplicates has many related objects.

This commit is contained in:
Richard Knop 2016-07-09 18:51:38 +08:00
parent 3324ab2063
commit 24501a3c1a
2 changed files with 85 additions and 0 deletions

View File

@ -186,6 +186,13 @@ func (scope *Scope) handleHasManyPreload(field *Field, conditions []interface{})
for j := 0; j < indirectScopeValue.Len(); j++ { for j := 0; j < indirectScopeValue.Len(); j++ {
object := indirect(indirectScopeValue.Index(j)) object := indirect(indirectScopeValue.Index(j))
objectRealValue := getValueFromFields(object, relation.AssociationForeignFieldNames) objectRealValue := getValueFromFields(object, relation.AssociationForeignFieldNames)
if j > 0 {
prevObject := indirect(indirectScopeValue.Index(j - 1))
prevObjectRealValue := getValueFromFields(prevObject, relation.AssociationForeignFieldNames)
if toString(prevObjectRealValue) == toString(objectRealValue) {
continue
}
}
if results, ok := preloadMap[toString(objectRealValue)]; ok { if results, ok := preloadMap[toString(objectRealValue)]; ok {
f := object.FieldByName(field.Name) f := object.FieldByName(field.Name)
f.Set(reflect.Append(f, results...)) f.Set(reflect.Append(f, results...))

View File

@ -1509,6 +1509,84 @@ func TestNilPointerSlice2(t *testing.T) {
} }
} }
func TestPrefixedPreloadDuplication(t *testing.T) {
type (
Level4 struct {
ID uint
Level3ID uint
}
Level3 struct {
ID uint
Level4s []*Level4
}
Level2 struct {
ID uint
Level3ID sql.NullInt64 `sql:"index"`
Level3 *Level3
}
Level1 struct {
ID uint
Level2ID sql.NullInt64 `sql:"index"`
Level2 *Level2
}
)
DB.DropTableIfExists(new(Level3))
DB.DropTableIfExists(new(Level4))
DB.DropTableIfExists(new(Level2))
DB.DropTableIfExists(new(Level1))
if err := DB.AutoMigrate(new(Level3), new(Level4), new(Level2), new(Level1)).Error; err != nil {
t.Error(err)
}
lvl := new(Level3)
if err := DB.Save(lvl).Error; err != nil {
t.Error(err)
}
sublvl1 := &Level4{Level3ID: lvl.ID}
if err := DB.Save(sublvl1).Error; err != nil {
t.Error(err)
}
sublvl2 := &Level4{Level3ID: lvl.ID}
if err := DB.Save(sublvl2).Error; err != nil {
t.Error(err)
}
lvl.Level4s = []*Level4{sublvl1, sublvl2}
want1 := Level1{
Level2: &Level2{
Level3: lvl,
},
}
if err := DB.Save(&want1).Error; err != nil {
t.Error(err)
}
want2 := Level1{
Level2: &Level2{
Level3: lvl,
},
}
if err := DB.Save(&want2).Error; err != nil {
t.Error(err)
}
want := []Level1{want1, want2}
var got []Level1
err := DB.Preload("Level2.Level3.Level4s").Find(&got).Error
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %s; want %s", toJSONString(got), toJSONString(want))
}
}
func toJSONString(v interface{}) []byte { func toJSONString(v interface{}) []byte {
r, _ := json.MarshalIndent(v, "", " ") r, _ := json.MarshalIndent(v, "", " ")
return r return r