Improve preload speed (#2058)

All credits to @vanjapt who came up with this patch.

Closes #1672
This commit is contained in:
maddie 2018-09-10 06:45:55 +08:00 committed by Jinzhu
parent 73e7561e20
commit 012d147974
1 changed files with 22 additions and 11 deletions

View File

@ -161,14 +161,17 @@ func (scope *Scope) handleHasOnePreload(field *Field, conditions []interface{})
)
if indirectScopeValue.Kind() == reflect.Slice {
foreignValuesToResults := make(map[string]reflect.Value)
for i := 0; i < resultsValue.Len(); i++ {
result := resultsValue.Index(i)
foreignValues := toString(getValueFromFields(result, relation.ForeignFieldNames))
foreignValuesToResults[foreignValues] = result
}
for j := 0; j < indirectScopeValue.Len(); j++ {
for i := 0; i < resultsValue.Len(); i++ {
result := resultsValue.Index(i)
foreignValues := getValueFromFields(result, relation.ForeignFieldNames)
if indirectValue := indirect(indirectScopeValue.Index(j)); equalAsString(getValueFromFields(indirectValue, relation.AssociationForeignFieldNames), foreignValues) {
indirectValue.FieldByName(field.Name).Set(result)
break
}
indirectValue := indirect(indirectScopeValue.Index(j))
valueString := toString(getValueFromFields(indirectValue, relation.AssociationForeignFieldNames))
if result, found := foreignValuesToResults[valueString]; found {
indirectValue.FieldByName(field.Name).Set(result)
}
}
} else {
@ -255,13 +258,21 @@ func (scope *Scope) handleBelongsToPreload(field *Field, conditions []interface{
indirectScopeValue = scope.IndirectValue()
)
foreignFieldToObjects := make(map[string][]*reflect.Value)
if indirectScopeValue.Kind() == reflect.Slice {
for j := 0; j < indirectScopeValue.Len(); j++ {
object := indirect(indirectScopeValue.Index(j))
valueString := toString(getValueFromFields(object, relation.ForeignFieldNames))
foreignFieldToObjects[valueString] = append(foreignFieldToObjects[valueString], &object)
}
}
for i := 0; i < resultsValue.Len(); i++ {
result := resultsValue.Index(i)
if indirectScopeValue.Kind() == reflect.Slice {
value := getValueFromFields(result, relation.AssociationForeignFieldNames)
for j := 0; j < indirectScopeValue.Len(); j++ {
object := indirect(indirectScopeValue.Index(j))
if equalAsString(getValueFromFields(object, relation.ForeignFieldNames), value) {
valueString := toString(getValueFromFields(result, relation.AssociationForeignFieldNames))
if objects, found := foreignFieldToObjects[valueString]; found {
for _, object := range objects {
object.FieldByName(field.Name).Set(result)
}
}