mirror of https://github.com/go-gorm/gorm.git
Return empty slice for associations with 0 results
When using `Preload` to include the results of a "has many" relationship, Gorm previously returned an uninitialized slice for any such relations that bore zero records. This distinction was most apparent when the results were marshalled to a JSON representation--a record with zero related records would be represented with `null`. For example, consider the following schema: id | name ---|------ 1 | Lorin 2 | Sue id | p_id | value ---|------|------------------- 1 | 1 | lorin@example.com 2 | 1 | lorin2@example.com Querying with: db.Preload("Email").Find(&people) And marshalling the resulting value of `people` to JSON would yield the following string: [ { "name": "Lorin", "email": [ "lorin@example.com", "lorin2@example.com" ] }, { "name": "Sue", "email": null } ] Beyond being inconsistent, the value `null` in this response differs semantically from the actual state of the database. The database actually has zero related records for the second user, so a JSON value of `[]` is appropriate. Update the callback that processes "has many" relationships to communicate empty query results with an empty slice.
This commit is contained in:
parent
5ec2f6ceb6
commit
f06d6412de
|
@ -186,9 +186,11 @@ 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)
|
||||||
|
f := object.FieldByName(field.Name)
|
||||||
if results, ok := preloadMap[toString(objectRealValue)]; ok {
|
if results, ok := preloadMap[toString(objectRealValue)]; ok {
|
||||||
f := object.FieldByName(field.Name)
|
|
||||||
f.Set(reflect.Append(f, results...))
|
f.Set(reflect.Append(f, results...))
|
||||||
|
} else {
|
||||||
|
f.Set(reflect.MakeSlice(f.Type(), 0, 0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -90,6 +90,8 @@ func TestPreload(t *testing.T) {
|
||||||
}
|
}
|
||||||
} else if len(user.Emails) != 0 {
|
} else if len(user.Emails) != 0 {
|
||||||
t.Errorf("should not preload any emails for other users when with condition")
|
t.Errorf("should not preload any emails for other users when with condition")
|
||||||
|
} else if user.Emails == nil {
|
||||||
|
t.Errorf("should return an empty slice to indicate zero results")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -592,8 +594,14 @@ func TestNestedPreload9(t *testing.T) {
|
||||||
},
|
},
|
||||||
Level2_1: Level2_1{
|
Level2_1: Level2_1{
|
||||||
Level1s: []Level1{
|
Level1s: []Level1{
|
||||||
{Value: "value3-3"},
|
{
|
||||||
{Value: "value4-4"},
|
Value: "value3-3",
|
||||||
|
Level0s: []Level0{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Value: "value4-4",
|
||||||
|
Level0s: []Level0{},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -657,6 +665,7 @@ func TestNestedPreload10(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Value: "bar 2",
|
Value: "bar 2",
|
||||||
|
LevelA3s: []*LevelA3{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, levelA2 := range want {
|
for _, levelA2 := range want {
|
||||||
|
|
Loading…
Reference in New Issue