increase performance m2m preload

This commit is contained in:
kimiby 2015-08-17 22:28:40 +03:00
parent e2689d335b
commit 07571d1adf
1 changed files with 19 additions and 41 deletions

View File

@ -202,20 +202,13 @@ func (scope *Scope) handleHasManyToManyPreload(field *Field, conditions []interf
destType = destType.Elem() destType = destType.Elem()
} }
var destKeys []string
var sourceKeys []string var sourceKeys []string
var linkHash = make(map[string][]string) var linkHash = make(map[string][]interface{})
for _, key := range joinTableHandler.DestinationForeignKeys() {
destKeys = append(destKeys, key.DBName)
}
for _, key := range joinTableHandler.SourceForeignKeys() { for _, key := range joinTableHandler.SourceForeignKeys() {
sourceKeys = append(sourceKeys, key.DBName) sourceKeys = append(sourceKeys, key.DBName)
} }
results := reflect.New(field.Struct.Type).Elem()
db := scope.NewDB().Table(scope.New(reflect.New(destType).Interface()).TableName()) db := scope.NewDB().Table(scope.New(reflect.New(destType).Interface()).TableName())
preloadJoinDB := joinTableHandler.PreloadWithJoin(joinTableHandler, db, scope.Value) preloadJoinDB := joinTableHandler.PreloadWithJoin(joinTableHandler, db, scope.Value)
if len(conditions) > 0 { if len(conditions) > 0 {
@ -250,7 +243,6 @@ func (scope *Scope) handleHasManyToManyPreload(field *Field, conditions []interf
scope.Err(rows.Scan(values...)) scope.Err(rows.Scan(values...))
var destKey []interface{}
var sourceKey []interface{} var sourceKey []interface{}
for index, column := range columns { for index, column := range columns {
@ -261,59 +253,45 @@ func (scope *Scope) handleHasManyToManyPreload(field *Field, conditions []interf
} else if v := reflect.ValueOf(value).Elem().Elem(); v.IsValid() { } else if v := reflect.ValueOf(value).Elem().Elem(); v.IsValid() {
field.Field.Set(v) field.Field.Set(v)
} }
} else if strInSlice(column, destKeys) {
destKey = append(destKey, *(value.(*interface{})))
} else if strInSlice(column, sourceKeys) { } else if strInSlice(column, sourceKeys) {
sourceKey = append(sourceKey, *(value.(*interface{}))) sourceKey = append(sourceKey, *(value.(*interface{})))
} }
} }
if len(destKey) != 0 && len(sourceKey) != 0 { if len(sourceKey) != 0 {
linkHash[toString(sourceKey)] = append(linkHash[toString(sourceKey)], toString(destKey)) if isPtr {
} linkHash[toString(sourceKey)] = append(linkHash[toString(sourceKey)], elem.Addr())
} else {
if isPtr { linkHash[toString(sourceKey)] = append(linkHash[toString(sourceKey)], elem)
results = reflect.Append(results, elem.Addr()) }
} else {
results = reflect.Append(results, elem)
} }
} }
if scope.IndirectValue().Kind() == reflect.Slice { if scope.IndirectValue().Kind() == reflect.Slice {
objects := scope.IndirectValue() objects := scope.IndirectValue()
for j := 0; j < objects.Len(); j++ { for j := 0; j < objects.Len(); j++ {
var checked []string
object := reflect.Indirect(objects.Index(j)) object := reflect.Indirect(objects.Index(j))
source := getRealValue(object, relation.AssociationForeignStructFieldNames) source := getRealValue(object, relation.AssociationForeignStructFieldNames)
links := linkHash[toString(source)]
for i := 0; i < results.Len(); i++ { for i := 0; i < len(links); i++ {
result := results.Index(i) f := object.FieldByName(field.Name)
value := getRealValue(result, relation.ForeignStructFieldNames) a := links[i].(reflect.Value)
f.Set(reflect.Append(f, a))
if strInSlice(toString(value), linkHash[toString(source)]) && !strInSlice(toString(value), checked) { continue
f := object.FieldByName(field.Name)
f.Set(reflect.Append(f, result))
checked = append(checked, toString(value))
continue
}
} }
} }
} else { } else {
object := scope.IndirectValue() object := scope.IndirectValue()
var checked []string
source := getRealValue(object, relation.AssociationForeignStructFieldNames) source := getRealValue(object, relation.AssociationForeignStructFieldNames)
for i := 0; i < results.Len(); i++ { links := linkHash[toString(source)]
result := results.Index(i)
value := getRealValue(result, relation.ForeignStructFieldNames)
if strInSlice(toString(value), linkHash[toString(source)]) && !strInSlice(toString(value), checked) { for i := 0; i < len(links); i++ {
f := object.FieldByName(field.Name) f := object.FieldByName(field.Name)
f.Set(reflect.Append(f, result)) a := links[i].(reflect.Value)
checked = append(checked, toString(value)) f.Set(reflect.Append(f, a))
continue continue
}
} }
} }
} }