fix: should check values has been saved instead of rel.Name
This commit is contained in:
		
							parent
							
								
									e55cdfa4b3
								
							
						
					
					
						commit
						bfffefb179
					
				@ -1,7 +1,6 @@
 | 
				
			|||||||
package callbacks
 | 
					package callbacks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -350,11 +349,9 @@ func saveAssociations(db *gorm.DB, rel *schema.Relationship, values interface{},
 | 
				
			|||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// stop save association loop
 | 
						// stop save association loop
 | 
				
			||||||
	savedRelKey := fmt.Sprintf("gorm:saved_relation_%s", rel.Name)
 | 
						if checkAssociationsSaved(db, values) {
 | 
				
			||||||
	if _, ok := db.Get(savedRelKey); ok {
 | 
					 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	db.Set(savedRelKey, true)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for name, ok := range selectColumns {
 | 
						for name, ok := range selectColumns {
 | 
				
			||||||
		columnName := ""
 | 
							columnName := ""
 | 
				
			||||||
@ -398,3 +395,23 @@ func saveAssociations(db *gorm.DB, rel *schema.Relationship, values interface{},
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return db.AddError(tx.Create(values).Error)
 | 
						return db.AddError(tx.Create(values).Error)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// check association values has been saved
 | 
				
			||||||
 | 
					func checkAssociationsSaved(db *gorm.DB, values interface{}) (saved bool) {
 | 
				
			||||||
 | 
						visitMapStoreKey := "gorm:saved_association_map"
 | 
				
			||||||
 | 
						var vistMap VisitMap
 | 
				
			||||||
 | 
						if visit, ok := db.Get(visitMapStoreKey); ok {
 | 
				
			||||||
 | 
							if v, ok := visit.(VisitMap); ok {
 | 
				
			||||||
 | 
								vistMap = v
 | 
				
			||||||
 | 
								if LoadOrStoreVisitMap(&vistMap, values) {
 | 
				
			||||||
 | 
									return true
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							vistMap = make(VisitMap)
 | 
				
			||||||
 | 
							LoadOrStoreVisitMap(&vistMap, values)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						db.Set(visitMapStoreKey, vistMap)
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
package callbacks
 | 
					package callbacks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"gorm.io/gorm"
 | 
						"gorm.io/gorm"
 | 
				
			||||||
@ -120,3 +121,47 @@ func checkMissingWhereConditions(db *gorm.DB) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type VisitMap = map[reflect.Value]bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Check if circular values
 | 
				
			||||||
 | 
					func LoadOrStoreVisitMap(origin *VisitMap, v interface{}) (loaded bool) {
 | 
				
			||||||
 | 
						if v == nil {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						value := reflect.ValueOf(v)
 | 
				
			||||||
 | 
						return loadOrStoreVisitMap(origin, value)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func loadOrStoreVisitMap(vistMap *VisitMap, v reflect.Value) (loaded bool) {
 | 
				
			||||||
 | 
						if v.Kind() == reflect.Ptr {
 | 
				
			||||||
 | 
							v = v.Elem()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch v.Kind() {
 | 
				
			||||||
 | 
						case reflect.Slice, reflect.Array:
 | 
				
			||||||
 | 
							sameCount := 0
 | 
				
			||||||
 | 
							for i := 0; i < v.Len(); i++ {
 | 
				
			||||||
 | 
								subv := v.Index(i)
 | 
				
			||||||
 | 
								if subv.CanAddr() {
 | 
				
			||||||
 | 
									if loadOrStoreVisitMap(vistMap, subv) {
 | 
				
			||||||
 | 
										sameCount++
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// all slice item already visited
 | 
				
			||||||
 | 
							if v.Len() == sameCount {
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						case reflect.Struct, reflect.Interface:
 | 
				
			||||||
 | 
							if v.CanAddr() {
 | 
				
			||||||
 | 
								p := v.Addr()
 | 
				
			||||||
 | 
								if _, ok := (*vistMap)[p]; ok {
 | 
				
			||||||
 | 
									return true
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									(*vistMap)[p] = true
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user