Skip to content

Commit

Permalink
fix: association concurrently appending (#6044)
Browse files Browse the repository at this point in the history
* fix: association concurrently appending

* fix: fix unit test

* fix: fix gofumpt
  • Loading branch information
black-06 authored Feb 18, 2023
1 parent aa89736 commit 42fc75c
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 2 deletions.
8 changes: 6 additions & 2 deletions association.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
40 changes: 40 additions & 0 deletions tests/associations_many2many_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package tests_test

import (
"fmt"
"sync"
"testing"

"gorm.io/gorm"
"gorm.io/gorm/clause"
. "gorm.io/gorm/utils/tests"
)

Expand Down Expand Up @@ -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")
}

0 comments on commit 42fc75c

Please sign in to comment.