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