forked from mirror/gorm
Fixed bug when preload duplicates has many related objects.
This commit is contained in:
parent
3324ab2063
commit
24501a3c1a
|
@ -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...))
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue