fix: association many2many duplicate elem
This commit is contained in:
		
							parent
							
								
									235c093bb9
								
							
						
					
					
						commit
						d4b7f3ddb8
					
				@ -253,6 +253,7 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 | 
				
			|||||||
					fieldType = reflect.PtrTo(fieldType)
 | 
										fieldType = reflect.PtrTo(fieldType)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				elems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10)
 | 
									elems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10)
 | 
				
			||||||
 | 
									distinctElems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10)
 | 
				
			||||||
				joins := reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(rel.JoinTable.ModelType)), 0, 10)
 | 
									joins := reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(rel.JoinTable.ModelType)), 0, 10)
 | 
				
			||||||
				objs := []reflect.Value{}
 | 
									objs := []reflect.Value{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -272,19 +273,31 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 | 
				
			|||||||
					joins = reflect.Append(joins, joinValue)
 | 
										joins = reflect.Append(joins, joinValue)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									identityMap := map[string]bool{}
 | 
				
			||||||
				appendToElems := func(v reflect.Value) {
 | 
									appendToElems := func(v reflect.Value) {
 | 
				
			||||||
					if _, zero := rel.Field.ValueOf(db.Statement.Context, v); !zero {
 | 
										if _, zero := rel.Field.ValueOf(db.Statement.Context, v); !zero {
 | 
				
			||||||
						f := reflect.Indirect(rel.Field.ReflectValueOf(db.Statement.Context, v))
 | 
											f := reflect.Indirect(rel.Field.ReflectValueOf(db.Statement.Context, v))
 | 
				
			||||||
 | 
					 | 
				
			||||||
						for i := 0; i < f.Len(); i++ {
 | 
											for i := 0; i < f.Len(); i++ {
 | 
				
			||||||
							elem := f.Index(i)
 | 
												elem := f.Index(i)
 | 
				
			||||||
 | 
												if !isPtr {
 | 
				
			||||||
							objs = append(objs, v)
 | 
													elem = elem.Addr()
 | 
				
			||||||
							if isPtr {
 | 
					 | 
				
			||||||
								elems = reflect.Append(elems, elem)
 | 
					 | 
				
			||||||
							} else {
 | 
					 | 
				
			||||||
								elems = reflect.Append(elems, elem.Addr())
 | 
					 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
 | 
												objs = append(objs, v)
 | 
				
			||||||
 | 
												elems = reflect.Append(elems, elem)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												relPrimaryValues := make([]interface{}, 0, len(rel.FieldSchema.PrimaryFields))
 | 
				
			||||||
 | 
												for _, pf := range rel.FieldSchema.PrimaryFields {
 | 
				
			||||||
 | 
													if pfv, ok := pf.ValueOf(db.Statement.Context, elem); !ok {
 | 
				
			||||||
 | 
														relPrimaryValues = append(relPrimaryValues, pfv)
 | 
				
			||||||
 | 
													}
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
												cacheKey := utils.ToStringKey(relPrimaryValues)
 | 
				
			||||||
 | 
												if len(relPrimaryValues) != len(rel.FieldSchema.PrimaryFields) || !identityMap[cacheKey] {
 | 
				
			||||||
 | 
													identityMap[cacheKey] = true
 | 
				
			||||||
 | 
													distinctElems = reflect.Append(distinctElems, elem)
 | 
				
			||||||
 | 
												}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@ -304,7 +317,7 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) {
 | 
				
			|||||||
				// optimize elems of reflect value length
 | 
									// optimize elems of reflect value length
 | 
				
			||||||
				if elemLen := elems.Len(); elemLen > 0 {
 | 
									if elemLen := elems.Len(); elemLen > 0 {
 | 
				
			||||||
					if v, ok := selectColumns[rel.Name+".*"]; !ok || v {
 | 
										if v, ok := selectColumns[rel.Name+".*"]; !ok || v {
 | 
				
			||||||
						saveAssociations(db, rel, elems, selectColumns, restricted, nil)
 | 
											saveAssociations(db, rel, distinctElems, selectColumns, restricted, nil)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					for i := 0; i < elemLen; i++ {
 | 
										for i := 0; i < elemLen; i++ {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
package tests_test
 | 
					package tests_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"testing"
 | 
						"gorm.io/gorm"
 | 
				
			||||||
 | 
					 | 
				
			||||||
	. "gorm.io/gorm/utils/tests"
 | 
						. "gorm.io/gorm/utils/tests"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestMany2ManyAssociation(t *testing.T) {
 | 
					func TestMany2ManyAssociation(t *testing.T) {
 | 
				
			||||||
@ -324,3 +324,29 @@ func TestSingleTableMany2ManyAssociationForSlice(t *testing.T) {
 | 
				
			|||||||
	DB.Model(&users).Association("Team").Clear()
 | 
						DB.Model(&users).Association("Team").Clear()
 | 
				
			||||||
	AssertAssociationCount(t, users, "Team", 0, "After Clear")
 | 
						AssertAssociationCount(t, users, "Team", 0, "After Clear")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestDuplicateMany2ManyAssociation(t *testing.T) {
 | 
				
			||||||
 | 
						user1 := User{Name: "TestDuplicateMany2ManyAssociation-1", Languages: []Language{
 | 
				
			||||||
 | 
							{Code: "TestDuplicateMany2ManyAssociation-language-1"},
 | 
				
			||||||
 | 
							{Code: "TestDuplicateMany2ManyAssociation-language-2"},
 | 
				
			||||||
 | 
						}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						user2 := User{Name: "TestDuplicateMany2ManyAssociation-1", Languages: []Language{
 | 
				
			||||||
 | 
							{Code: "TestDuplicateMany2ManyAssociation-language-1"},
 | 
				
			||||||
 | 
							{Code: "TestDuplicateMany2ManyAssociation-language-3"},
 | 
				
			||||||
 | 
						}}
 | 
				
			||||||
 | 
						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("Languages").Where("id = ?", user1.ID).First(&findUser1).Error
 | 
				
			||||||
 | 
						AssertEqual(t, nil, err)
 | 
				
			||||||
 | 
						AssertEqual(t, user1, findUser1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var findUser2 User
 | 
				
			||||||
 | 
						err = DB.Preload("Languages").Where("id = ?", user2.ID).First(&findUser2).Error
 | 
				
			||||||
 | 
						AssertEqual(t, nil, err)
 | 
				
			||||||
 | 
						AssertEqual(t, user2, findUser2)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user