Fix create duplicated value when updating nested has many relationship, close #4796
This commit is contained in:
		
							parent
							
								
									45e804dd3f
								
							
						
					
					
						commit
						27e2753c9d
					
				| @ -7,6 +7,7 @@ import ( | ||||
| 	"gorm.io/gorm" | ||||
| 	"gorm.io/gorm/clause" | ||||
| 	"gorm.io/gorm/schema" | ||||
| 	"gorm.io/gorm/utils" | ||||
| ) | ||||
| 
 | ||||
| func SaveBeforeAssociations(create bool) func(db *gorm.DB) { | ||||
| @ -182,6 +183,7 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) { | ||||
| 					fieldType = reflect.PtrTo(fieldType) | ||||
| 				} | ||||
| 				elems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10) | ||||
| 				identityMap := map[string]bool{} | ||||
| 				appendToElems := func(v reflect.Value) { | ||||
| 					if _, zero := rel.Field.ValueOf(v); !zero { | ||||
| 						f := reflect.Indirect(rel.Field.ReflectValueOf(v)) | ||||
| @ -197,10 +199,21 @@ func SaveAfterAssociations(create bool) func(db *gorm.DB) { | ||||
| 								} | ||||
| 							} | ||||
| 
 | ||||
| 							if isPtr { | ||||
| 								elems = reflect.Append(elems, elem) | ||||
| 							} else { | ||||
| 								elems = reflect.Append(elems, elem.Addr()) | ||||
| 							relPrimaryValues := make([]interface{}, 0, len(rel.FieldSchema.PrimaryFields)) | ||||
| 							for _, pf := range rel.FieldSchema.PrimaryFields { | ||||
| 								if pfv, ok := pf.ValueOf(elem); !ok { | ||||
| 									relPrimaryValues = append(relPrimaryValues, pfv) | ||||
| 								} | ||||
| 							} | ||||
| 
 | ||||
| 							cacheKey := utils.ToStringKey(relPrimaryValues) | ||||
| 							if len(relPrimaryValues) == 0 || (len(relPrimaryValues) == len(rel.FieldSchema.PrimaryFields) && !identityMap[cacheKey]) { | ||||
| 								identityMap[cacheKey] = true | ||||
| 								if isPtr { | ||||
| 									elems = reflect.Append(elems, elem) | ||||
| 								} else { | ||||
| 									elems = reflect.Append(elems, elem.Addr()) | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
|  | ||||
| @ -178,19 +178,21 @@ func TestForeignKeyConstraintsBelongsTo(t *testing.T) { | ||||
| } | ||||
| 
 | ||||
| func TestFullSaveAssociations(t *testing.T) { | ||||
| 	coupon := &Coupon{ | ||||
| 		ID: "full-save-association-coupon1", | ||||
| 		AppliesToProduct: []*CouponProduct{ | ||||
| 			{ | ||||
| 				CouponId:  "full-save-association-coupon1", | ||||
| 				ProductId: "full-save-association-product1", | ||||
| 			}, | ||||
| 		}, | ||||
| 		AmountOff:  10, | ||||
| 		PercentOff: 0.0, | ||||
| 	} | ||||
| 
 | ||||
| 	err := DB. | ||||
| 		Session(&gorm.Session{FullSaveAssociations: true}). | ||||
| 		Create(&Coupon{ | ||||
| 			ID: "full-save-association-coupon1", | ||||
| 			AppliesToProduct: []*CouponProduct{ | ||||
| 				{ | ||||
| 					CouponId:  "full-save-association-coupon1", | ||||
| 					ProductId: "full-save-association-product1", | ||||
| 				}, | ||||
| 			}, | ||||
| 			AmountOff:  10, | ||||
| 			PercentOff: 0.0, | ||||
| 		}).Error | ||||
| 		Create(coupon).Error | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		t.Errorf("Failed, got error: %v", err) | ||||
| @ -203,4 +205,9 @@ func TestFullSaveAssociations(t *testing.T) { | ||||
| 	if DB.First(&CouponProduct{}, "coupon_id = ? AND product_id = ?", "full-save-association-coupon1", "full-save-association-product1").Error != nil { | ||||
| 		t.Errorf("Failed to query saved association") | ||||
| 	} | ||||
| 
 | ||||
| 	orders := []Order{{Num: "order1", Coupon: coupon}, {Num: "order2", Coupon: coupon}} | ||||
| 	if err := DB.Create(&orders).Error; err != nil { | ||||
| 		t.Errorf("failed to create orders, got %v", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -427,7 +427,7 @@ func TestCompositePrimaryKeysAssociations(t *testing.T) { | ||||
| 
 | ||||
| 	DB.Migrator().DropTable(&Label{}, &Book{}) | ||||
| 	if err := DB.AutoMigrate(&Label{}, &Book{}); err != nil { | ||||
| 		t.Fatalf("failed to migrate") | ||||
| 		t.Fatalf("failed to migrate, got %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	book := Book{ | ||||
|  | ||||
| @ -87,7 +87,7 @@ func OpenTestConnection() (db *gorm.DB, err error) { | ||||
| 
 | ||||
| func RunMigrations() { | ||||
| 	var err error | ||||
| 	allModels := []interface{}{&User{}, &Account{}, &Pet{}, &Company{}, &Toy{}, &Language{}, &Coupon{}, &CouponProduct{}} | ||||
| 	allModels := []interface{}{&User{}, &Account{}, &Pet{}, &Company{}, &Toy{}, &Language{}, &Coupon{}, &CouponProduct{}, &Order{}} | ||||
| 	rand.Seed(time.Now().UnixNano()) | ||||
| 	rand.Shuffle(len(allModels), func(i, j int) { allModels[i], allModels[j] = allModels[j], allModels[i] }) | ||||
| 
 | ||||
|  | ||||
| @ -72,3 +72,10 @@ type CouponProduct struct { | ||||
| 	CouponId  string `gorm:"primarykey; size:255"` | ||||
| 	ProductId string `gorm:"primarykey; size:255"` | ||||
| } | ||||
| 
 | ||||
| type Order struct { | ||||
| 	gorm.Model | ||||
| 	Num      string | ||||
| 	Coupon   *Coupon | ||||
| 	CouponID string | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Jinzhu
						Jinzhu