fix: association concurrently appending (#6044)
* fix: association concurrently appending * fix: fix unit test * fix: fix gofumpt
This commit is contained in:
		
							parent
							
								
									aa89736db2
								
							
						
					
					
						commit
						42fc75cb2c
					
				| @ -353,9 +353,13 @@ func (association *Association) saveAssociation(clear bool, values ...interface{ | |||||||
| 			} | 			} | ||||||
| 		case schema.HasMany, schema.Many2Many: | 		case schema.HasMany, schema.Many2Many: | ||||||
| 			elemType := association.Relationship.Field.IndirectFieldType.Elem() | 			elemType := association.Relationship.Field.IndirectFieldType.Elem() | ||||||
| 			fieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(association.DB.Statement.Context, source)) | 			oldFieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(association.DB.Statement.Context, source)) | ||||||
|  | 			var fieldValue reflect.Value | ||||||
| 			if clear { | 			if clear { | ||||||
| 				fieldValue = reflect.New(association.Relationship.Field.IndirectFieldType).Elem() | 				fieldValue = reflect.MakeSlice(oldFieldValue.Type(), 0, oldFieldValue.Cap()) | ||||||
|  | 			} else { | ||||||
|  | 				fieldValue = reflect.MakeSlice(oldFieldValue.Type(), oldFieldValue.Len(), oldFieldValue.Cap()) | ||||||
|  | 				reflect.Copy(fieldValue, oldFieldValue) | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			appendToFieldValues := func(ev reflect.Value) { | 			appendToFieldValues := func(ev reflect.Value) { | ||||||
|  | |||||||
| @ -1,9 +1,12 @@ | |||||||
| package tests_test | package tests_test | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"sync" | ||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
| 	"gorm.io/gorm" | 	"gorm.io/gorm" | ||||||
|  | 	"gorm.io/gorm/clause" | ||||||
| 	. "gorm.io/gorm/utils/tests" | 	. "gorm.io/gorm/utils/tests" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -353,3 +356,40 @@ func TestDuplicateMany2ManyAssociation(t *testing.T) { | |||||||
| 	AssertEqual(t, nil, err) | 	AssertEqual(t, nil, err) | ||||||
| 	AssertEqual(t, user2, findUser2) | 	AssertEqual(t, user2, findUser2) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestConcurrentMany2ManyAssociation(t *testing.T) { | ||||||
|  | 	db, err := OpenTestConnection() | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("open test connection failed, err: %+v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	count := 3 | ||||||
|  | 
 | ||||||
|  | 	var languages []Language | ||||||
|  | 	for i := 0; i < count; i++ { | ||||||
|  | 		language := Language{Code: fmt.Sprintf("consurrent %d", i)} | ||||||
|  | 		db.Create(&language) | ||||||
|  | 		languages = append(languages, language) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	user := User{} | ||||||
|  | 	db.Create(&user) | ||||||
|  | 	db.Preload("Languages").FirstOrCreate(&user) | ||||||
|  | 
 | ||||||
|  | 	var wg sync.WaitGroup | ||||||
|  | 	for i := 0; i < count; i++ { | ||||||
|  | 		wg.Add(1) | ||||||
|  | 		go func(user User, language Language) { | ||||||
|  | 			err := db.Model(&user).Association("Languages").Append(&language) | ||||||
|  | 			AssertEqual(t, err, nil) | ||||||
|  | 
 | ||||||
|  | 			wg.Done() | ||||||
|  | 		}(user, languages[i]) | ||||||
|  | 	} | ||||||
|  | 	wg.Wait() | ||||||
|  | 
 | ||||||
|  | 	var find User | ||||||
|  | 	err = db.Preload(clause.Associations).Where("id = ?", user.ID).First(&find).Error | ||||||
|  | 	AssertEqual(t, err, nil) | ||||||
|  | 	AssertAssociationCount(t, find, "Languages", int64(count), "after concurrent append") | ||||||
|  | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 black-06
						black-06