From aeb9b56f19f069f8639aec993aee4bfa6432d995 Mon Sep 17 00:00:00 2001 From: Larry Morales Jordan Date: Thu, 6 May 2021 08:07:23 -0500 Subject: [PATCH] Remove many to many TX condition for EagerPreload (#645) * Remove the need to use Tx when loading many to many associations * replace TX access to create a new tx.Store.Transaction() object --- preload_associations.go | 105 +++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 50 deletions(-) diff --git a/preload_associations.go b/preload_associations.go index c7c8b6c5..1ba4d5a2 100644 --- a/preload_associations.go +++ b/preload_associations.go @@ -437,72 +437,77 @@ func preloadManyToMany(tx *Connection, asoc *AssociationMetaInfo, mmi *ModelMeta manyToManyTableName = strings.TrimSpace(manyToManyTableName[:strings.Index(manyToManyTableName, ":")]) } - if tx.TX != nil { - sql := fmt.Sprintf("SELECT %s, %s FROM %s WHERE %s in (?)", modelAssociationName, assocFkName, manyToManyTableName, modelAssociationName) - sql, args, _ := sqlx.In(sql, ids) - sql = tx.Dialect.TranslateSQL(sql) - log(logging.SQL, sql, args...) - rows, err := tx.TX.Queryx(sql, args...) + sql := fmt.Sprintf("SELECT %s, %s FROM %s WHERE %s in (?)", modelAssociationName, assocFkName, manyToManyTableName, modelAssociationName) + sql, args, _ := sqlx.In(sql, ids) + sql = tx.Dialect.TranslateSQL(sql) + log(logging.SQL, sql, args...) + + cn, err := tx.Store.Transaction() + if err != nil { + return err + } + + rows, err := cn.Queryx(sql, args...) + if err != nil { + return err + } + + mapAssoc := map[string][]interface{}{} + fkids := []interface{}{} + for rows.Next() { + row, err := rows.SliceScan() if err != nil { return err } - - mapAssoc := map[string][]interface{}{} - fkids := []interface{}{} - for rows.Next() { - row, err := rows.SliceScan() - if err != nil { - return err + if len(row) > 0 { + if _, ok := row[0].([]uint8); ok { // -> it's UUID + row[0] = string(row[0].([]uint8)) } - if len(row) > 0 { - if _, ok := row[0].([]uint8); ok { // -> it's UUID - row[0] = string(row[0].([]uint8)) - } - if _, ok := row[1].([]uint8); ok { // -> it's UUID - row[1] = string(row[1].([]uint8)) - } - key := fmt.Sprintf("%v", row[0]) - mapAssoc[key] = append(mapAssoc[key], row[1]) - fkids = append(fkids, row[1]) + if _, ok := row[1].([]uint8); ok { // -> it's UUID + row[1] = string(row[1].([]uint8)) } + key := fmt.Sprintf("%v", row[0]) + mapAssoc[key] = append(mapAssoc[key], row[1]) + fkids = append(fkids, row[1]) } + } - q := tx.Q() - q.eager = false - q.eagerFields = []string{} + q := tx.Q() + q.eager = false + q.eagerFields = []string{} - if strings.TrimSpace(asoc.Field.Tag.Get("order_by")) != "" { - q.Order(asoc.Field.Tag.Get("order_by")) - } + if strings.TrimSpace(asoc.Field.Tag.Get("order_by")) != "" { + q.Order(asoc.Field.Tag.Get("order_by")) + } - slice := asoc.toSlice() - q.Where("id in (?)", fkids).All(slice.Interface()) + slice := asoc.toSlice() + q.Where("id in (?)", fkids).All(slice.Interface()) - // 2.2) load all nested associations from this assoc. - if asocNestedFields, ok := mmi.nestedFields[asoc.Path]; ok { - for _, asocNestedField := range asocNestedFields { - if err := preload(tx, slice.Interface(), asocNestedField); err != nil { - return err - } + // 2.2) load all nested associations from this assoc. + if asocNestedFields, ok := mmi.nestedFields[asoc.Path]; ok { + for _, asocNestedField := range asocNestedFields { + if err := preload(tx, slice.Interface(), asocNestedField); err != nil { + return err } } + } - // 3) iterate over every model and fill it with the assoc. - mmi.iterate(func(mvalue reflect.Value) { - id := mmi.mapper.FieldByName(mvalue, "ID").Interface() - if assocFkIds, ok := mapAssoc[fmt.Sprintf("%v", id)]; ok { - modelAssociationField := mmi.mapper.FieldByName(mvalue, asoc.Name) - for i := 0; i < slice.Elem().Len(); i++ { - asocValue := slice.Elem().Index(i) - for _, fkid := range assocFkIds { - if fmt.Sprintf("%v", fkid) == fmt.Sprintf("%v", mmi.mapper.FieldByName(asocValue, "ID").Interface()) { - modelAssociationField.Set(reflect.Append(modelAssociationField, asocValue)) - } + // 3) iterate over every model and fill it with the assoc. + mmi.iterate(func(mvalue reflect.Value) { + id := mmi.mapper.FieldByName(mvalue, "ID").Interface() + if assocFkIds, ok := mapAssoc[fmt.Sprintf("%v", id)]; ok { + modelAssociationField := mmi.mapper.FieldByName(mvalue, asoc.Name) + for i := 0; i < slice.Elem().Len(); i++ { + asocValue := slice.Elem().Index(i) + for _, fkid := range assocFkIds { + if fmt.Sprintf("%v", fkid) == fmt.Sprintf("%v", mmi.mapper.FieldByName(asocValue, "ID").Interface()) { + modelAssociationField.Set(reflect.Append(modelAssociationField, asocValue)) } } } - }) - } + } + }) + return nil }