mirror of https://github.com/go-gorm/gorm.git
perf: merge nested preload query when using join (#6990)
* pref: merge nest preload query * fix: preload test
This commit is contained in:
parent
5553ff3dcb
commit
85299bfca7
|
@ -123,8 +123,18 @@ func preloadEntryPoint(db *gorm.DB, joins []string, relationships *schema.Relati
|
|||
if joined, nestedJoins := isJoined(name); joined {
|
||||
switch rv := db.Statement.ReflectValue; rv.Kind() {
|
||||
case reflect.Slice, reflect.Array:
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
reflectValue := rel.Field.ReflectValueOf(db.Statement.Context, rv.Index(i))
|
||||
if rv.Len() > 0 {
|
||||
reflectValue := rel.FieldSchema.MakeSlice().Elem()
|
||||
reflectValue.SetLen(rv.Len())
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
frv := rel.Field.ReflectValueOf(db.Statement.Context, rv.Index(i))
|
||||
if frv.Kind() != reflect.Ptr {
|
||||
reflectValue.Index(i).Set(frv.Addr())
|
||||
} else {
|
||||
reflectValue.Index(i).Set(frv)
|
||||
}
|
||||
}
|
||||
|
||||
tx := preloadDB(db, reflectValue, reflectValue.Interface())
|
||||
if err := preloadEntryPoint(tx, nestedJoins, &tx.Statement.Schema.Relationships, preloadMap[name], associationsConds); err != nil {
|
||||
return err
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
package tests_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
|
@ -337,7 +337,7 @@ func TestNestedPreloadWithNestedJoin(t *testing.T) {
|
|||
DB.Migrator().DropTable(&Preload{}, &Join{}, &Nested{}, &Value{})
|
||||
DB.Migrator().AutoMigrate(&Preload{}, &Join{}, &Nested{}, &Value{})
|
||||
|
||||
value := Value{
|
||||
value1 := Value{
|
||||
Name: "value",
|
||||
Nested: Nested{
|
||||
Preloads: []*Preload{
|
||||
|
@ -346,32 +346,98 @@ func TestNestedPreloadWithNestedJoin(t *testing.T) {
|
|||
Join: Join{Value: "j1"},
|
||||
},
|
||||
}
|
||||
if err := DB.Create(&value).Error; err != nil {
|
||||
value2 := Value{
|
||||
Name: "value2",
|
||||
Nested: Nested{
|
||||
Preloads: []*Preload{
|
||||
{Value: "p3"}, {Value: "p4"}, {Value: "p5"},
|
||||
},
|
||||
Join: Join{Value: "j2"},
|
||||
},
|
||||
}
|
||||
|
||||
values := []*Value{&value1, &value2}
|
||||
if err := DB.Create(&values).Error; err != nil {
|
||||
t.Errorf("failed to create value, got err: %v", err)
|
||||
}
|
||||
|
||||
var find1 Value
|
||||
err := DB.Joins("Nested").Joins("Nested.Join").Preload("Nested.Preloads").First(&find1).Error
|
||||
err := DB.Joins("Nested").Joins("Nested.Join").Preload("Nested.Preloads").First(&find1, value1.ID).Error
|
||||
if err != nil {
|
||||
t.Errorf("failed to find value, got err: %v", err)
|
||||
}
|
||||
AssertEqual(t, find1, value)
|
||||
AssertEqual(t, find1, value1)
|
||||
|
||||
var find2 Value
|
||||
// Joins will automatically add Nested queries.
|
||||
err = DB.Joins("Nested.Join").Preload("Nested.Preloads").First(&find2).Error
|
||||
err = DB.Joins("Nested.Join").Preload("Nested.Preloads").First(&find2, value2.ID).Error
|
||||
if err != nil {
|
||||
t.Errorf("failed to find value, got err: %v", err)
|
||||
}
|
||||
AssertEqual(t, find2, value)
|
||||
AssertEqual(t, find2, value2)
|
||||
|
||||
var finds []Value
|
||||
err = DB.Joins("Nested.Join").Joins("Nested").Preload("Nested.Preloads").Find(&finds).Error
|
||||
if err != nil {
|
||||
t.Errorf("failed to find value, got err: %v", err)
|
||||
}
|
||||
require.Len(t, finds, 1)
|
||||
AssertEqual(t, finds[0], value)
|
||||
AssertEqual(t, len(finds), 2)
|
||||
AssertEqual(t, finds[0], value1)
|
||||
AssertEqual(t, finds[1], value2)
|
||||
}
|
||||
|
||||
func TestMergeNestedPreloadWithNestedJoin(t *testing.T) {
|
||||
users := []User{
|
||||
{
|
||||
Name: "TestMergeNestedPreloadWithNestedJoin-1",
|
||||
Manager: &User{
|
||||
Name: "Alexis Manager",
|
||||
Tools: []Tools{
|
||||
{Name: "Alexis Tool 1"},
|
||||
{Name: "Alexis Tool 2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "TestMergeNestedPreloadWithNestedJoin-2",
|
||||
Manager: &User{
|
||||
Name: "Jinzhu Manager",
|
||||
Tools: []Tools{
|
||||
{Name: "Jinzhu Tool 1"},
|
||||
{Name: "Jinzhu Tool 2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
DB.Create(&users)
|
||||
|
||||
query := make([]string, 0)
|
||||
sess := DB.Session(&gorm.Session{Logger: Tracer{
|
||||
Logger: DB.Config.Logger,
|
||||
Test: func(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
|
||||
sql, _ := fc()
|
||||
query = append(query, sql)
|
||||
},
|
||||
}})
|
||||
|
||||
var result []User
|
||||
err := sess.
|
||||
Joins("Manager").
|
||||
Preload("Manager.Tools").
|
||||
Where("users.name Like ?", "TestMergeNestedPreloadWithNestedJoin%").
|
||||
Find(&result).Error
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("failed to preload and find users: %v", err)
|
||||
}
|
||||
|
||||
AssertEqual(t, result, users)
|
||||
AssertEqual(t, len(query), 2) // Check preload queries are merged
|
||||
|
||||
if !regexp.MustCompile(`SELECT \* FROM .*tools.* WHERE .*IN.*`).MatchString(query[0]) {
|
||||
t.Fatalf("Expected first query to preload manager tools, got: %s", query[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmbedPreload(t *testing.T) {
|
||||
|
|
Loading…
Reference in New Issue