fix: association concurrently appending (#6044)

* fix: association concurrently appending

* fix: fix unit test

* fix: fix gofumpt
This commit is contained in:
black-06 2023-02-18 09:19:24 +08:00 committed by GitHub
parent aa89736db2
commit 42fc75cb2c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 2 deletions

View File

@ -353,9 +353,13 @@ func (association *Association) saveAssociation(clear bool, values ...interface{
}
case schema.HasMany, schema.Many2Many:
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 {
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) {

View File

@ -1,9 +1,12 @@
package tests_test
import (
"fmt"
"sync"
"testing"
"gorm.io/gorm"
"gorm.io/gorm/clause"
. "gorm.io/gorm/utils/tests"
)
@ -353,3 +356,40 @@ func TestDuplicateMany2ManyAssociation(t *testing.T) {
AssertEqual(t, nil, err)
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")
}