Save associations based on creatable/updatable permission, close #4056
This commit is contained in:
		
							parent
							
								
									4373aa01ab
								
							
						
					
					
						commit
						deff0594ee
					
				| @ -9,79 +9,81 @@ import ( | |||||||
| 	"gorm.io/gorm/schema" | 	"gorm.io/gorm/schema" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func SaveBeforeAssociations(db *gorm.DB) { | func SaveBeforeAssociations(create bool) func(db *gorm.DB) { | ||||||
| 	if db.Error == nil && db.Statement.Schema != nil { | 	return func(db *gorm.DB) { | ||||||
| 		selectColumns, restricted := db.Statement.SelectAndOmitColumns(true, false) | 		if db.Error == nil && db.Statement.Schema != nil { | ||||||
|  | 			selectColumns, restricted := db.Statement.SelectAndOmitColumns(create, !create) | ||||||
| 
 | 
 | ||||||
| 		// Save Belongs To associations
 | 			// Save Belongs To associations
 | ||||||
| 		for _, rel := range db.Statement.Schema.Relationships.BelongsTo { | 			for _, rel := range db.Statement.Schema.Relationships.BelongsTo { | ||||||
| 			if v, ok := selectColumns[rel.Name]; (ok && !v) || (!ok && restricted) { | 				if v, ok := selectColumns[rel.Name]; (ok && !v) || (!ok && restricted) { | ||||||
| 				continue | 					continue | ||||||
| 			} | 				} | ||||||
| 
 | 
 | ||||||
| 			setupReferences := func(obj reflect.Value, elem reflect.Value) { | 				setupReferences := func(obj reflect.Value, elem reflect.Value) { | ||||||
| 				for _, ref := range rel.References { | 					for _, ref := range rel.References { | ||||||
| 					if !ref.OwnPrimaryKey { | 						if !ref.OwnPrimaryKey { | ||||||
| 						pv, _ := ref.PrimaryKey.ValueOf(elem) | 							pv, _ := ref.PrimaryKey.ValueOf(elem) | ||||||
| 						db.AddError(ref.ForeignKey.Set(obj, pv)) | 							db.AddError(ref.ForeignKey.Set(obj, pv)) | ||||||
| 
 | 
 | ||||||
| 						if dest, ok := db.Statement.Dest.(map[string]interface{}); ok { | 							if dest, ok := db.Statement.Dest.(map[string]interface{}); ok { | ||||||
| 							dest[ref.ForeignKey.DBName] = pv | 								dest[ref.ForeignKey.DBName] = pv | ||||||
| 							if _, ok := dest[rel.Name]; ok { | 								if _, ok := dest[rel.Name]; ok { | ||||||
| 								dest[rel.Name] = elem.Interface() | 									dest[rel.Name] = elem.Interface() | ||||||
|  | 								} | ||||||
| 							} | 							} | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			} |  | ||||||
| 
 | 
 | ||||||
| 			switch db.Statement.ReflectValue.Kind() { | 				switch db.Statement.ReflectValue.Kind() { | ||||||
| 			case reflect.Slice, reflect.Array: | 				case reflect.Slice, reflect.Array: | ||||||
| 				var ( | 					var ( | ||||||
| 					objs      []reflect.Value | 						objs      []reflect.Value | ||||||
| 					fieldType = rel.Field.FieldType | 						fieldType = rel.Field.FieldType | ||||||
| 					isPtr     = fieldType.Kind() == reflect.Ptr | 						isPtr     = fieldType.Kind() == reflect.Ptr | ||||||
| 				) | 					) | ||||||
| 
 | 
 | ||||||
| 				if !isPtr { | 					if !isPtr { | ||||||
| 					fieldType = reflect.PtrTo(fieldType) | 						fieldType = reflect.PtrTo(fieldType) | ||||||
| 				} | 					} | ||||||
| 
 | 
 | ||||||
| 				elems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10) | 					elems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10) | ||||||
| 				for i := 0; i < db.Statement.ReflectValue.Len(); i++ { | 					for i := 0; i < db.Statement.ReflectValue.Len(); i++ { | ||||||
| 					obj := db.Statement.ReflectValue.Index(i) | 						obj := db.Statement.ReflectValue.Index(i) | ||||||
| 
 | 
 | ||||||
| 					if reflect.Indirect(obj).Kind() == reflect.Struct { | 						if reflect.Indirect(obj).Kind() == reflect.Struct { | ||||||
| 						if _, zero := rel.Field.ValueOf(obj); !zero { // check belongs to relation value
 | 							if _, zero := rel.Field.ValueOf(obj); !zero { // check belongs to relation value
 | ||||||
| 							rv := rel.Field.ReflectValueOf(obj) // relation reflect value
 | 								rv := rel.Field.ReflectValueOf(obj) // relation reflect value
 | ||||||
| 							objs = append(objs, obj) | 								objs = append(objs, obj) | ||||||
| 							if isPtr { | 								if isPtr { | ||||||
| 								elems = reflect.Append(elems, rv) | 									elems = reflect.Append(elems, rv) | ||||||
| 							} else { | 								} else { | ||||||
| 								elems = reflect.Append(elems, rv.Addr()) | 									elems = reflect.Append(elems, rv.Addr()) | ||||||
|  | 								} | ||||||
|  | 							} | ||||||
|  | 						} else { | ||||||
|  | 							break | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if elems.Len() > 0 { | ||||||
|  | 						if saveAssociations(db, rel, elems.Interface(), selectColumns, restricted, nil) == nil { | ||||||
|  | 							for i := 0; i < elems.Len(); i++ { | ||||||
|  | 								setupReferences(objs[i], elems.Index(i)) | ||||||
| 							} | 							} | ||||||
| 						} | 						} | ||||||
| 					} else { |  | ||||||
| 						break |  | ||||||
| 					} | 					} | ||||||
| 				} | 				case reflect.Struct: | ||||||
| 
 | 					if _, zero := rel.Field.ValueOf(db.Statement.ReflectValue); !zero { | ||||||
| 				if elems.Len() > 0 { | 						rv := rel.Field.ReflectValueOf(db.Statement.ReflectValue) // relation reflect value
 | ||||||
| 					if saveAssociations(db, rel, elems.Interface(), selectColumns, restricted, nil) == nil { | 						if rv.Kind() != reflect.Ptr { | ||||||
| 						for i := 0; i < elems.Len(); i++ { | 							rv = rv.Addr() | ||||||
| 							setupReferences(objs[i], elems.Index(i)) |  | ||||||
| 						} | 						} | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			case reflect.Struct: |  | ||||||
| 				if _, zero := rel.Field.ValueOf(db.Statement.ReflectValue); !zero { |  | ||||||
| 					rv := rel.Field.ReflectValueOf(db.Statement.ReflectValue) // relation reflect value
 |  | ||||||
| 					if rv.Kind() != reflect.Ptr { |  | ||||||
| 						rv = rv.Addr() |  | ||||||
| 					} |  | ||||||
| 
 | 
 | ||||||
| 					if saveAssociations(db, rel, rv.Interface(), selectColumns, restricted, nil) == nil { | 						if saveAssociations(db, rel, rv.Interface(), selectColumns, restricted, nil) == nil { | ||||||
| 						setupReferences(db.Statement.ReflectValue, rv) | 							setupReferences(db.Statement.ReflectValue, rv) | ||||||
|  | 						} | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| @ -89,53 +91,133 @@ func SaveBeforeAssociations(db *gorm.DB) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func SaveAfterAssociations(db *gorm.DB) { | func SaveAfterAssociations(create bool) func(db *gorm.DB) { | ||||||
| 	if db.Error == nil && db.Statement.Schema != nil { | 	return func(db *gorm.DB) { | ||||||
| 		selectColumns, restricted := db.Statement.SelectAndOmitColumns(true, false) | 		if db.Error == nil && db.Statement.Schema != nil { | ||||||
|  | 			selectColumns, restricted := db.Statement.SelectAndOmitColumns(create, !create) | ||||||
| 
 | 
 | ||||||
| 		// Save Has One associations
 | 			// Save Has One associations
 | ||||||
| 		for _, rel := range db.Statement.Schema.Relationships.HasOne { | 			for _, rel := range db.Statement.Schema.Relationships.HasOne { | ||||||
| 			if v, ok := selectColumns[rel.Name]; (ok && !v) || (!ok && restricted) { | 				if v, ok := selectColumns[rel.Name]; (ok && !v) || (!ok && restricted) { | ||||||
| 				continue | 					continue | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				switch db.Statement.ReflectValue.Kind() { | ||||||
|  | 				case reflect.Slice, reflect.Array: | ||||||
|  | 					var ( | ||||||
|  | 						fieldType = rel.Field.FieldType | ||||||
|  | 						isPtr     = fieldType.Kind() == reflect.Ptr | ||||||
|  | 					) | ||||||
|  | 
 | ||||||
|  | 					if !isPtr { | ||||||
|  | 						fieldType = reflect.PtrTo(fieldType) | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					elems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10) | ||||||
|  | 
 | ||||||
|  | 					for i := 0; i < db.Statement.ReflectValue.Len(); i++ { | ||||||
|  | 						obj := db.Statement.ReflectValue.Index(i) | ||||||
|  | 
 | ||||||
|  | 						if reflect.Indirect(obj).Kind() == reflect.Struct { | ||||||
|  | 							if _, zero := rel.Field.ValueOf(obj); !zero { | ||||||
|  | 								rv := rel.Field.ReflectValueOf(obj) | ||||||
|  | 								if rv.Kind() != reflect.Ptr { | ||||||
|  | 									rv = rv.Addr() | ||||||
|  | 								} | ||||||
|  | 
 | ||||||
|  | 								for _, ref := range rel.References { | ||||||
|  | 									if ref.OwnPrimaryKey { | ||||||
|  | 										fv, _ := ref.PrimaryKey.ValueOf(obj) | ||||||
|  | 										db.AddError(ref.ForeignKey.Set(rv, fv)) | ||||||
|  | 									} else if ref.PrimaryValue != "" { | ||||||
|  | 										db.AddError(ref.ForeignKey.Set(rv, ref.PrimaryValue)) | ||||||
|  | 									} | ||||||
|  | 								} | ||||||
|  | 
 | ||||||
|  | 								elems = reflect.Append(elems, rv) | ||||||
|  | 							} | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 
 | ||||||
|  | 					if elems.Len() > 0 { | ||||||
|  | 						assignmentColumns := []string{} | ||||||
|  | 						for _, ref := range rel.References { | ||||||
|  | 							assignmentColumns = append(assignmentColumns, ref.ForeignKey.DBName) | ||||||
|  | 						} | ||||||
|  | 
 | ||||||
|  | 						saveAssociations(db, rel, elems.Interface(), selectColumns, restricted, assignmentColumns) | ||||||
|  | 					} | ||||||
|  | 				case reflect.Struct: | ||||||
|  | 					if _, zero := rel.Field.ValueOf(db.Statement.ReflectValue); !zero { | ||||||
|  | 						f := rel.Field.ReflectValueOf(db.Statement.ReflectValue) | ||||||
|  | 						if f.Kind() != reflect.Ptr { | ||||||
|  | 							f = f.Addr() | ||||||
|  | 						} | ||||||
|  | 
 | ||||||
|  | 						assignmentColumns := []string{} | ||||||
|  | 						for _, ref := range rel.References { | ||||||
|  | 							if ref.OwnPrimaryKey { | ||||||
|  | 								fv, _ := ref.PrimaryKey.ValueOf(db.Statement.ReflectValue) | ||||||
|  | 								ref.ForeignKey.Set(f, fv) | ||||||
|  | 							} else if ref.PrimaryValue != "" { | ||||||
|  | 								ref.ForeignKey.Set(f, ref.PrimaryValue) | ||||||
|  | 							} | ||||||
|  | 							assignmentColumns = append(assignmentColumns, ref.ForeignKey.DBName) | ||||||
|  | 						} | ||||||
|  | 
 | ||||||
|  | 						saveAssociations(db, rel, f.Interface(), selectColumns, restricted, assignmentColumns) | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			switch db.Statement.ReflectValue.Kind() { | 			// Save Has Many associations
 | ||||||
| 			case reflect.Slice, reflect.Array: | 			for _, rel := range db.Statement.Schema.Relationships.HasMany { | ||||||
| 				var ( | 				if v, ok := selectColumns[rel.Name]; (ok && !v) || (!ok && restricted) { | ||||||
| 					fieldType = rel.Field.FieldType | 					continue | ||||||
| 					isPtr     = fieldType.Kind() == reflect.Ptr | 				} | ||||||
| 				) |  | ||||||
| 
 | 
 | ||||||
|  | 				fieldType := rel.Field.IndirectFieldType.Elem() | ||||||
|  | 				isPtr := fieldType.Kind() == reflect.Ptr | ||||||
| 				if !isPtr { | 				if !isPtr { | ||||||
| 					fieldType = reflect.PtrTo(fieldType) | 					fieldType = reflect.PtrTo(fieldType) | ||||||
| 				} | 				} | ||||||
| 
 |  | ||||||
| 				elems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10) | 				elems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10) | ||||||
|  | 				appendToElems := func(v reflect.Value) { | ||||||
|  | 					if _, zero := rel.Field.ValueOf(v); !zero { | ||||||
|  | 						f := reflect.Indirect(rel.Field.ReflectValueOf(v)) | ||||||
| 
 | 
 | ||||||
| 				for i := 0; i < db.Statement.ReflectValue.Len(); i++ { | 						for i := 0; i < f.Len(); i++ { | ||||||
| 					obj := db.Statement.ReflectValue.Index(i) | 							elem := f.Index(i) | ||||||
| 
 |  | ||||||
| 					if reflect.Indirect(obj).Kind() == reflect.Struct { |  | ||||||
| 						if _, zero := rel.Field.ValueOf(obj); !zero { |  | ||||||
| 							rv := rel.Field.ReflectValueOf(obj) |  | ||||||
| 							if rv.Kind() != reflect.Ptr { |  | ||||||
| 								rv = rv.Addr() |  | ||||||
| 							} |  | ||||||
| 
 |  | ||||||
| 							for _, ref := range rel.References { | 							for _, ref := range rel.References { | ||||||
| 								if ref.OwnPrimaryKey { | 								if ref.OwnPrimaryKey { | ||||||
| 									fv, _ := ref.PrimaryKey.ValueOf(obj) | 									pv, _ := ref.PrimaryKey.ValueOf(v) | ||||||
| 									db.AddError(ref.ForeignKey.Set(rv, fv)) | 									ref.ForeignKey.Set(elem, pv) | ||||||
| 								} else if ref.PrimaryValue != "" { | 								} else if ref.PrimaryValue != "" { | ||||||
| 									db.AddError(ref.ForeignKey.Set(rv, ref.PrimaryValue)) | 									ref.ForeignKey.Set(elem, ref.PrimaryValue) | ||||||
| 								} | 								} | ||||||
| 							} | 							} | ||||||
| 
 | 
 | ||||||
| 							elems = reflect.Append(elems, rv) | 							if isPtr { | ||||||
|  | 								elems = reflect.Append(elems, elem) | ||||||
|  | 							} else { | ||||||
|  | 								elems = reflect.Append(elems, elem.Addr()) | ||||||
|  | 							} | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
|  | 				switch db.Statement.ReflectValue.Kind() { | ||||||
|  | 				case reflect.Slice, reflect.Array: | ||||||
|  | 					for i := 0; i < db.Statement.ReflectValue.Len(); i++ { | ||||||
|  | 						obj := db.Statement.ReflectValue.Index(i) | ||||||
|  | 						if reflect.Indirect(obj).Kind() == reflect.Struct { | ||||||
|  | 							appendToElems(obj) | ||||||
|  | 						} | ||||||
|  | 					} | ||||||
|  | 				case reflect.Struct: | ||||||
|  | 					appendToElems(db.Statement.ReflectValue) | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
| 				if elems.Len() > 0 { | 				if elems.Len() > 0 { | ||||||
| 					assignmentColumns := []string{} | 					assignmentColumns := []string{} | ||||||
| 					for _, ref := range rel.References { | 					for _, ref := range rel.References { | ||||||
| @ -144,162 +226,84 @@ func SaveAfterAssociations(db *gorm.DB) { | |||||||
| 
 | 
 | ||||||
| 					saveAssociations(db, rel, elems.Interface(), selectColumns, restricted, assignmentColumns) | 					saveAssociations(db, rel, elems.Interface(), selectColumns, restricted, assignmentColumns) | ||||||
| 				} | 				} | ||||||
| 			case reflect.Struct: | 			} | ||||||
| 				if _, zero := rel.Field.ValueOf(db.Statement.ReflectValue); !zero { |  | ||||||
| 					f := rel.Field.ReflectValueOf(db.Statement.ReflectValue) |  | ||||||
| 					if f.Kind() != reflect.Ptr { |  | ||||||
| 						f = f.Addr() |  | ||||||
| 					} |  | ||||||
| 
 | 
 | ||||||
| 					assignmentColumns := []string{} | 			// Save Many2Many associations
 | ||||||
|  | 			for _, rel := range db.Statement.Schema.Relationships.Many2Many { | ||||||
|  | 				if v, ok := selectColumns[rel.Name]; (ok && !v) || (!ok && restricted) { | ||||||
|  | 					continue | ||||||
|  | 				} | ||||||
|  | 
 | ||||||
|  | 				fieldType := rel.Field.IndirectFieldType.Elem() | ||||||
|  | 				isPtr := fieldType.Kind() == reflect.Ptr | ||||||
|  | 				if !isPtr { | ||||||
|  | 					fieldType = reflect.PtrTo(fieldType) | ||||||
|  | 				} | ||||||
|  | 				elems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10) | ||||||
|  | 				joins := reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(rel.JoinTable.ModelType)), 0, 10) | ||||||
|  | 				objs := []reflect.Value{} | ||||||
|  | 
 | ||||||
|  | 				appendToJoins := func(obj reflect.Value, elem reflect.Value) { | ||||||
|  | 					joinValue := reflect.New(rel.JoinTable.ModelType) | ||||||
| 					for _, ref := range rel.References { | 					for _, ref := range rel.References { | ||||||
| 						if ref.OwnPrimaryKey { | 						if ref.OwnPrimaryKey { | ||||||
| 							fv, _ := ref.PrimaryKey.ValueOf(db.Statement.ReflectValue) | 							fv, _ := ref.PrimaryKey.ValueOf(obj) | ||||||
| 							ref.ForeignKey.Set(f, fv) | 							ref.ForeignKey.Set(joinValue, fv) | ||||||
| 						} else if ref.PrimaryValue != "" { | 						} else if ref.PrimaryValue != "" { | ||||||
| 							ref.ForeignKey.Set(f, ref.PrimaryValue) | 							ref.ForeignKey.Set(joinValue, ref.PrimaryValue) | ||||||
|  | 						} else { | ||||||
|  | 							fv, _ := ref.PrimaryKey.ValueOf(elem) | ||||||
|  | 							ref.ForeignKey.Set(joinValue, fv) | ||||||
| 						} | 						} | ||||||
| 						assignmentColumns = append(assignmentColumns, ref.ForeignKey.DBName) |  | ||||||
| 					} | 					} | ||||||
| 
 | 					joins = reflect.Append(joins, joinValue) | ||||||
| 					saveAssociations(db, rel, f.Interface(), selectColumns, restricted, assignmentColumns) |  | ||||||
| 				} | 				} | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		// Save Has Many associations
 | 				appendToElems := func(v reflect.Value) { | ||||||
| 		for _, rel := range db.Statement.Schema.Relationships.HasMany { | 					if _, zero := rel.Field.ValueOf(v); !zero { | ||||||
| 			if v, ok := selectColumns[rel.Name]; (ok && !v) || (!ok && restricted) { | 						f := reflect.Indirect(rel.Field.ReflectValueOf(v)) | ||||||
| 				continue |  | ||||||
| 			} |  | ||||||
| 
 | 
 | ||||||
| 			fieldType := rel.Field.IndirectFieldType.Elem() | 						for i := 0; i < f.Len(); i++ { | ||||||
| 			isPtr := fieldType.Kind() == reflect.Ptr | 							elem := f.Index(i) | ||||||
| 			if !isPtr { |  | ||||||
| 				fieldType = reflect.PtrTo(fieldType) |  | ||||||
| 			} |  | ||||||
| 			elems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10) |  | ||||||
| 			appendToElems := func(v reflect.Value) { |  | ||||||
| 				if _, zero := rel.Field.ValueOf(v); !zero { |  | ||||||
| 					f := reflect.Indirect(rel.Field.ReflectValueOf(v)) |  | ||||||
| 
 | 
 | ||||||
| 					for i := 0; i < f.Len(); i++ { | 							objs = append(objs, v) | ||||||
| 						elem := f.Index(i) | 							if isPtr { | ||||||
| 						for _, ref := range rel.References { | 								elems = reflect.Append(elems, elem) | ||||||
| 							if ref.OwnPrimaryKey { | 							} else { | ||||||
| 								pv, _ := ref.PrimaryKey.ValueOf(v) | 								elems = reflect.Append(elems, elem.Addr()) | ||||||
| 								ref.ForeignKey.Set(elem, pv) |  | ||||||
| 							} else if ref.PrimaryValue != "" { |  | ||||||
| 								ref.ForeignKey.Set(elem, ref.PrimaryValue) |  | ||||||
| 							} | 							} | ||||||
| 						} | 						} | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
| 
 | 
 | ||||||
| 						if isPtr { | 				switch db.Statement.ReflectValue.Kind() { | ||||||
| 							elems = reflect.Append(elems, elem) | 				case reflect.Slice, reflect.Array: | ||||||
| 						} else { | 					for i := 0; i < db.Statement.ReflectValue.Len(); i++ { | ||||||
| 							elems = reflect.Append(elems, elem.Addr()) | 						obj := db.Statement.ReflectValue.Index(i) | ||||||
|  | 						if reflect.Indirect(obj).Kind() == reflect.Struct { | ||||||
|  | 							appendToElems(obj) | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
|  | 				case reflect.Struct: | ||||||
|  | 					appendToElems(db.Statement.ReflectValue) | ||||||
| 				} | 				} | ||||||
| 			} |  | ||||||
| 
 | 
 | ||||||
| 			switch db.Statement.ReflectValue.Kind() { | 				if elems.Len() > 0 { | ||||||
| 			case reflect.Slice, reflect.Array: | 					if v, ok := selectColumns[rel.Name+".*"]; !ok || v { | ||||||
| 				for i := 0; i < db.Statement.ReflectValue.Len(); i++ { | 						saveAssociations(db, rel, elems.Interface(), selectColumns, restricted, nil) | ||||||
| 					obj := db.Statement.ReflectValue.Index(i) | 					} | ||||||
| 					if reflect.Indirect(obj).Kind() == reflect.Struct { | 
 | ||||||
| 						appendToElems(obj) | 					for i := 0; i < elems.Len(); i++ { | ||||||
|  | 						appendToJoins(objs[i], elems.Index(i)) | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			case reflect.Struct: |  | ||||||
| 				appendToElems(db.Statement.ReflectValue) |  | ||||||
| 			} |  | ||||||
| 
 | 
 | ||||||
| 			if elems.Len() > 0 { | 				if joins.Len() > 0 { | ||||||
| 				assignmentColumns := []string{} | 					db.AddError(db.Session(&gorm.Session{NewDB: true}).Clauses(clause.OnConflict{DoNothing: true}).Session(&gorm.Session{ | ||||||
| 				for _, ref := range rel.References { | 						SkipHooks:                db.Statement.SkipHooks, | ||||||
| 					assignmentColumns = append(assignmentColumns, ref.ForeignKey.DBName) | 						DisableNestedTransaction: true, | ||||||
|  | 					}).Create(joins.Interface()).Error) | ||||||
| 				} | 				} | ||||||
| 
 |  | ||||||
| 				saveAssociations(db, rel, elems.Interface(), selectColumns, restricted, assignmentColumns) |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// Save Many2Many associations
 |  | ||||||
| 		for _, rel := range db.Statement.Schema.Relationships.Many2Many { |  | ||||||
| 			if v, ok := selectColumns[rel.Name]; (ok && !v) || (!ok && restricted) { |  | ||||||
| 				continue |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			fieldType := rel.Field.IndirectFieldType.Elem() |  | ||||||
| 			isPtr := fieldType.Kind() == reflect.Ptr |  | ||||||
| 			if !isPtr { |  | ||||||
| 				fieldType = reflect.PtrTo(fieldType) |  | ||||||
| 			} |  | ||||||
| 			elems := reflect.MakeSlice(reflect.SliceOf(fieldType), 0, 10) |  | ||||||
| 			joins := reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(rel.JoinTable.ModelType)), 0, 10) |  | ||||||
| 			objs := []reflect.Value{} |  | ||||||
| 
 |  | ||||||
| 			appendToJoins := func(obj reflect.Value, elem reflect.Value) { |  | ||||||
| 				joinValue := reflect.New(rel.JoinTable.ModelType) |  | ||||||
| 				for _, ref := range rel.References { |  | ||||||
| 					if ref.OwnPrimaryKey { |  | ||||||
| 						fv, _ := ref.PrimaryKey.ValueOf(obj) |  | ||||||
| 						ref.ForeignKey.Set(joinValue, fv) |  | ||||||
| 					} else if ref.PrimaryValue != "" { |  | ||||||
| 						ref.ForeignKey.Set(joinValue, ref.PrimaryValue) |  | ||||||
| 					} else { |  | ||||||
| 						fv, _ := ref.PrimaryKey.ValueOf(elem) |  | ||||||
| 						ref.ForeignKey.Set(joinValue, fv) |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 				joins = reflect.Append(joins, joinValue) |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			appendToElems := func(v reflect.Value) { |  | ||||||
| 				if _, zero := rel.Field.ValueOf(v); !zero { |  | ||||||
| 					f := reflect.Indirect(rel.Field.ReflectValueOf(v)) |  | ||||||
| 
 |  | ||||||
| 					for i := 0; i < f.Len(); i++ { |  | ||||||
| 						elem := f.Index(i) |  | ||||||
| 
 |  | ||||||
| 						objs = append(objs, v) |  | ||||||
| 						if isPtr { |  | ||||||
| 							elems = reflect.Append(elems, elem) |  | ||||||
| 						} else { |  | ||||||
| 							elems = reflect.Append(elems, elem.Addr()) |  | ||||||
| 						} |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			switch db.Statement.ReflectValue.Kind() { |  | ||||||
| 			case reflect.Slice, reflect.Array: |  | ||||||
| 				for i := 0; i < db.Statement.ReflectValue.Len(); i++ { |  | ||||||
| 					obj := db.Statement.ReflectValue.Index(i) |  | ||||||
| 					if reflect.Indirect(obj).Kind() == reflect.Struct { |  | ||||||
| 						appendToElems(obj) |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			case reflect.Struct: |  | ||||||
| 				appendToElems(db.Statement.ReflectValue) |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			if elems.Len() > 0 { |  | ||||||
| 				if v, ok := selectColumns[rel.Name+".*"]; !ok || v { |  | ||||||
| 					saveAssociations(db, rel, elems.Interface(), selectColumns, restricted, nil) |  | ||||||
| 				} |  | ||||||
| 
 |  | ||||||
| 				for i := 0; i < elems.Len(); i++ { |  | ||||||
| 					appendToJoins(objs[i], elems.Index(i)) |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			if joins.Len() > 0 { |  | ||||||
| 				db.AddError(db.Session(&gorm.Session{NewDB: true}).Clauses(clause.OnConflict{DoNothing: true}).Session(&gorm.Session{ |  | ||||||
| 					SkipHooks:                db.Statement.SkipHooks, |  | ||||||
| 					DisableNestedTransaction: true, |  | ||||||
| 				}).Create(joins.Interface()).Error) |  | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -17,9 +17,9 @@ func RegisterDefaultCallbacks(db *gorm.DB, config *Config) { | |||||||
| 	createCallback := db.Callback().Create() | 	createCallback := db.Callback().Create() | ||||||
| 	createCallback.Match(enableTransaction).Register("gorm:begin_transaction", BeginTransaction) | 	createCallback.Match(enableTransaction).Register("gorm:begin_transaction", BeginTransaction) | ||||||
| 	createCallback.Register("gorm:before_create", BeforeCreate) | 	createCallback.Register("gorm:before_create", BeforeCreate) | ||||||
| 	createCallback.Register("gorm:save_before_associations", SaveBeforeAssociations) | 	createCallback.Register("gorm:save_before_associations", SaveBeforeAssociations(true)) | ||||||
| 	createCallback.Register("gorm:create", Create(config)) | 	createCallback.Register("gorm:create", Create(config)) | ||||||
| 	createCallback.Register("gorm:save_after_associations", SaveAfterAssociations) | 	createCallback.Register("gorm:save_after_associations", SaveAfterAssociations(true)) | ||||||
| 	createCallback.Register("gorm:after_create", AfterCreate) | 	createCallback.Register("gorm:after_create", AfterCreate) | ||||||
| 	createCallback.Match(enableTransaction).Register("gorm:commit_or_rollback_transaction", CommitOrRollbackTransaction) | 	createCallback.Match(enableTransaction).Register("gorm:commit_or_rollback_transaction", CommitOrRollbackTransaction) | ||||||
| 
 | 
 | ||||||
| @ -40,9 +40,9 @@ func RegisterDefaultCallbacks(db *gorm.DB, config *Config) { | |||||||
| 	updateCallback.Match(enableTransaction).Register("gorm:begin_transaction", BeginTransaction) | 	updateCallback.Match(enableTransaction).Register("gorm:begin_transaction", BeginTransaction) | ||||||
| 	updateCallback.Register("gorm:setup_reflect_value", SetupUpdateReflectValue) | 	updateCallback.Register("gorm:setup_reflect_value", SetupUpdateReflectValue) | ||||||
| 	updateCallback.Register("gorm:before_update", BeforeUpdate) | 	updateCallback.Register("gorm:before_update", BeforeUpdate) | ||||||
| 	updateCallback.Register("gorm:save_before_associations", SaveBeforeAssociations) | 	updateCallback.Register("gorm:save_before_associations", SaveBeforeAssociations(false)) | ||||||
| 	updateCallback.Register("gorm:update", Update) | 	updateCallback.Register("gorm:update", Update) | ||||||
| 	updateCallback.Register("gorm:save_after_associations", SaveAfterAssociations) | 	updateCallback.Register("gorm:save_after_associations", SaveAfterAssociations(false)) | ||||||
| 	updateCallback.Register("gorm:after_update", AfterUpdate) | 	updateCallback.Register("gorm:after_update", AfterUpdate) | ||||||
| 	updateCallback.Match(enableTransaction).Register("gorm:commit_or_rollback_transaction", CommitOrRollbackTransaction) | 	updateCallback.Match(enableTransaction).Register("gorm:commit_or_rollback_transaction", CommitOrRollbackTransaction) | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -235,6 +235,8 @@ func Parse(dest interface{}, cacheStore *sync.Map, namer Namer) (*Schema, error) | |||||||
| 			if field.DataType == "" && (field.Creatable || field.Updatable || field.Readable) { | 			if field.DataType == "" && (field.Creatable || field.Updatable || field.Readable) { | ||||||
| 				if schema.parseRelation(field); schema.err != nil { | 				if schema.parseRelation(field); schema.err != nil { | ||||||
| 					return schema, schema.err | 					return schema, schema.err | ||||||
|  | 				} else { | ||||||
|  | 					schema.FieldsByName[field.Name] = field | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Jinzhu
						Jinzhu