fix: use reflect.Append when preloading nested associations
This commit is contained in:
		
							parent
							
								
									5e599a07ec
								
							
						
					
					
						commit
						d7421cf7ba
					
				| @ -125,13 +125,15 @@ func preloadEntryPoint(db *gorm.DB, joins []string, relationships *schema.Relati | ||||
| 				case reflect.Slice, reflect.Array: | ||||
| 					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()) | ||||
| 								reflectValue = reflect.Append(reflectValue, frv.Addr()) | ||||
| 							} else { | ||||
| 								reflectValue.Index(i).Set(frv) | ||||
| 								if frv.IsNil() { | ||||
| 									continue | ||||
| 								} | ||||
| 								reflectValue = reflect.Append(reflectValue, frv) | ||||
| 							} | ||||
| 						} | ||||
| 
 | ||||
|  | ||||
| @ -67,9 +67,10 @@ func (schema Schema) String() string { | ||||
| } | ||||
| 
 | ||||
| func (schema Schema) MakeSlice() reflect.Value { | ||||
| 	slice := reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(schema.ModelType)), 0, 20) | ||||
| 	slice := reflect.MakeSlice(reflect.SliceOf(reflect.PointerTo(schema.ModelType)), 0, 20) | ||||
| 	results := reflect.New(slice.Type()) | ||||
| 	results.Elem().Set(slice) | ||||
| 
 | ||||
| 	return results | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -11,7 +11,7 @@ require ( | ||||
| 	gorm.io/driver/postgres v1.5.7 | ||||
| 	gorm.io/driver/sqlite v1.5.5 | ||||
| 	gorm.io/driver/sqlserver v1.5.3 | ||||
| 	gorm.io/gorm v1.25.9 | ||||
| 	gorm.io/gorm v1.25.10 | ||||
| ) | ||||
| 
 | ||||
| require ( | ||||
|  | ||||
| @ -1,10 +1,12 @@ | ||||
| package tests_test | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 	"sort" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"gorm.io/gorm" | ||||
| 	. "gorm.io/gorm/utils/tests" | ||||
| ) | ||||
| @ -400,3 +402,75 @@ func TestNestedJoins(t *testing.T) { | ||||
| 		CheckPet(t, *user.Manager.NamedPet, *users2[idx].Manager.NamedPet) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestJoinsPreload_Issue7013(t *testing.T) { | ||||
| 	manager := &User{Name: "Manager"} | ||||
| 	DB.Create(manager) | ||||
| 
 | ||||
| 	var userIDs []uint | ||||
| 	for i := 0; i < 21; i++ { | ||||
| 		user := &User{Name: fmt.Sprintf("User%d", i), ManagerID: &manager.ID} | ||||
| 		DB.Create(user) | ||||
| 		userIDs = append(userIDs, user.ID) | ||||
| 	} | ||||
| 
 | ||||
| 	var entries []User | ||||
| 	assert.NotPanics(t, func() { | ||||
| 		assert.NoError(t, | ||||
| 			DB.Debug().Preload("Manager.Team"). | ||||
| 				Joins("Manager.Company"). | ||||
| 				Find(&entries).Error) | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| func TestJoinsPreload_Issue7013_RelationEmpty(t *testing.T) { | ||||
| 	type ( | ||||
| 		Furniture struct { | ||||
| 			gorm.Model | ||||
| 			OwnerID *uint | ||||
| 		} | ||||
| 
 | ||||
| 		Owner struct { | ||||
| 			gorm.Model | ||||
| 			Furnitures []Furniture | ||||
| 			CompanyID  *uint | ||||
| 			Company    Company | ||||
| 		} | ||||
| 
 | ||||
| 		Building struct { | ||||
| 			gorm.Model | ||||
| 			Name    string | ||||
| 			OwnerID *uint | ||||
| 			Owner   Owner | ||||
| 		} | ||||
| 	) | ||||
| 
 | ||||
| 	DB.Migrator().DropTable(&Building{}, &Owner{}, &Furniture{}) | ||||
| 	DB.Migrator().AutoMigrate(&Building{}, &Owner{}, &Furniture{}) | ||||
| 
 | ||||
| 	home := &Building{Name: "relation_empty"} | ||||
| 	DB.Create(home) | ||||
| 
 | ||||
| 	var entries []Building | ||||
| 	assert.NotPanics(t, func() { | ||||
| 		assert.NoError(t, | ||||
| 			DB.Debug().Preload("Owner.Furnitures"). | ||||
| 				Joins("Owner.Company"). | ||||
| 				Find(&entries).Error) | ||||
| 	}) | ||||
| 
 | ||||
| 	AssertEqual(t, entries, []Building{{Model: home.Model, Name: "relation_empty", Owner: Owner{Company: Company{}}}}) | ||||
| } | ||||
| 
 | ||||
| func TestJoinsPreload_Issue7013_NoEntries(t *testing.T) { | ||||
| 	var entries []User | ||||
| 	assert.NotPanics(t, func() { | ||||
| 		assert.NoError(t, | ||||
| 			DB.Debug().Preload("Manager.Team"). | ||||
| 				Joins("Manager.Company"). | ||||
| 				Where("false"). | ||||
| 				Find(&entries).Error) | ||||
| 	}) | ||||
| 
 | ||||
| 	AssertEqual(t, len(entries), 0) | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Emilien Kofman
						Emilien Kofman