fix: many2many association with duplicate belongs to elem (#6206)
This commit is contained in:
		
							parent
							
								
									05bb9d6106
								
							
						
					
					
						commit
						ccc3cb758a
					
				| @ -51,25 +51,40 @@ func SaveBeforeAssociations(create bool) func(db *gorm.DB) { | |||||||
| 					} | 					} | ||||||
| 
 | 
 | ||||||
| 					elems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10) | 					elems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10) | ||||||
|  | 					distinctElems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10) | ||||||
|  | 					identityMap := map[string]bool{} | ||||||
| 					for i := 0; i < rValLen; i++ { | 					for i := 0; i < rValLen; i++ { | ||||||
| 						obj := db.Statement.ReflectValue.Index(i) | 						obj := db.Statement.ReflectValue.Index(i) | ||||||
| 						if reflect.Indirect(obj).Kind() != reflect.Struct { | 						if reflect.Indirect(obj).Kind() != reflect.Struct { | ||||||
| 							break | 							break | ||||||
| 						} | 						} | ||||||
| 
 |  | ||||||
| 						if _, zero := rel.Field.ValueOf(db.Statement.Context, obj); !zero { // check belongs to relation value
 | 						if _, zero := rel.Field.ValueOf(db.Statement.Context, obj); !zero { // check belongs to relation value
 | ||||||
| 							rv := rel.Field.ReflectValueOf(db.Statement.Context, obj) // relation reflect value
 | 							rv := rel.Field.ReflectValueOf(db.Statement.Context, obj) // relation reflect value
 | ||||||
|  | 							if !isPtr { | ||||||
|  | 								rv = rv.Addr() | ||||||
|  | 							} | ||||||
| 							objs = append(objs, obj) | 							objs = append(objs, obj) | ||||||
| 							if isPtr { | 							elems = reflect.Append(elems, rv) | ||||||
| 								elems = reflect.Append(elems, rv) | 
 | ||||||
| 							} else { | 							relPrimaryValues := make([]interface{}, 0, len(rel.FieldSchema.PrimaryFields)) | ||||||
| 								elems = reflect.Append(elems, rv.Addr()) | 							for _, pf := range rel.FieldSchema.PrimaryFields { | ||||||
|  | 								if pfv, ok := pf.ValueOf(db.Statement.Context, rv); !ok { | ||||||
|  | 									relPrimaryValues = append(relPrimaryValues, pfv) | ||||||
|  | 								} | ||||||
|  | 							} | ||||||
|  | 							cacheKey := utils.ToStringKey(relPrimaryValues...) | ||||||
|  | 							if len(relPrimaryValues) != len(rel.FieldSchema.PrimaryFields) || !identityMap[cacheKey] { | ||||||
|  | 								if cacheKey != "" { // has primary fields
 | ||||||
|  | 									identityMap[cacheKey] = true | ||||||
|  | 								} | ||||||
|  | 
 | ||||||
|  | 								distinctElems = reflect.Append(distinctElems, rv) | ||||||
| 							} | 							} | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| 
 | 
 | ||||||
| 					if elems.Len() > 0 { | 					if elems.Len() > 0 { | ||||||
| 						if saveAssociations(db, rel, elems, selectColumns, restricted, nil) == nil { | 						if saveAssociations(db, rel, distinctElems, selectColumns, restricted, nil) == nil { | ||||||
| 							for i := 0; i < elems.Len(); i++ { | 							for i := 0; i < elems.Len(); i++ { | ||||||
| 								setupReferences(objs[i], elems.Index(i)) | 								setupReferences(objs[i], elems.Index(i)) | ||||||
| 							} | 							} | ||||||
|  | |||||||
| @ -393,3 +393,33 @@ func TestConcurrentMany2ManyAssociation(t *testing.T) { | |||||||
| 	AssertEqual(t, err, nil) | 	AssertEqual(t, err, nil) | ||||||
| 	AssertAssociationCount(t, find, "Languages", int64(count), "after concurrent append") | 	AssertAssociationCount(t, find, "Languages", int64(count), "after concurrent append") | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestMany2ManyDuplicateBelongsToAssociation(t *testing.T) { | ||||||
|  | 	user1 := User{Name: "TestMany2ManyDuplicateBelongsToAssociation-1", Friends: []*User{ | ||||||
|  | 		{Name: "TestMany2ManyDuplicateBelongsToAssociation-friend-1", Company: Company{ | ||||||
|  | 			ID:   1, | ||||||
|  | 			Name: "Test-company-1", | ||||||
|  | 		}}, | ||||||
|  | 	}} | ||||||
|  | 
 | ||||||
|  | 	user2 := User{Name: "TestMany2ManyDuplicateBelongsToAssociation-2", Friends: []*User{ | ||||||
|  | 		{Name: "TestMany2ManyDuplicateBelongsToAssociation-friend-2", Company: Company{ | ||||||
|  | 			ID:   1, | ||||||
|  | 			Name: "Test-company-1", | ||||||
|  | 		}}, | ||||||
|  | 	}} | ||||||
|  | 	users := []*User{&user1, &user2} | ||||||
|  | 	var err error | ||||||
|  | 	err = DB.Session(&gorm.Session{FullSaveAssociations: true}).Save(users).Error | ||||||
|  | 	AssertEqual(t, nil, err) | ||||||
|  | 
 | ||||||
|  | 	var findUser1 User | ||||||
|  | 	err = DB.Preload("Friends.Company").Where("id = ?", user1.ID).First(&findUser1).Error | ||||||
|  | 	AssertEqual(t, nil, err) | ||||||
|  | 	AssertEqual(t, user1, findUser1) | ||||||
|  | 
 | ||||||
|  | 	var findUser2 User | ||||||
|  | 	err = DB.Preload("Friends.Company").Where("id = ?", user2.ID).First(&findUser2).Error | ||||||
|  | 	AssertEqual(t, nil, err) | ||||||
|  | 	AssertEqual(t, user2, findUser2) | ||||||
|  | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 bsmith-auth0
						bsmith-auth0