Skip to content

Commit 1851ee5

Browse files
authoredJul 1, 2020
Fix has_many associations with embedded structs (jinzhu#2)
* Fix has_many association in embedded struct * Remove need for association_foreignkey with embedded has_many. * Fix more calls to getForeignField * Rename test models for consistency
1 parent 7cc9c13 commit 1851ee5

File tree

2 files changed

+62
-9
lines changed

2 files changed

+62
-9
lines changed
 

‎model_struct.go

+15-9
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@ func getForeignField(column string, fields []*StructField) *StructField {
152152

153153
// GetModelStruct get value's model struct, relationships based on struct and tag definition
154154
func (scope *Scope) GetModelStruct() *ModelStruct {
155+
return scope.getModelStruct(scope, make([]*StructField, 0))
156+
}
157+
158+
func (scope *Scope) getModelStruct(rootScope *Scope, allFields []*StructField) *ModelStruct {
155159
var modelStruct ModelStruct
156160
// Scope value can't be nil
157161
if scope.Value == nil {
@@ -237,7 +241,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
237241
field.IsNormal = true
238242
} else if _, ok := field.TagSettingsGet("EMBEDDED"); ok || fieldStruct.Anonymous {
239243
// is embedded struct
240-
for _, subField := range scope.New(fieldValue).GetModelStruct().StructFields {
244+
for _, subField := range scope.New(fieldValue).getModelStruct(rootScope, allFields).StructFields {
241245
subField = subField.clone()
242246
subField.Names = append([]string{fieldStruct.Name}, subField.Names...)
243247
if prefix, ok := field.TagSettingsGet("EMBEDDED_PREFIX"); ok {
@@ -261,6 +265,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
261265
}
262266

263267
modelStruct.StructFields = append(modelStruct.StructFields, subField)
268+
allFields = append(allFields, subField)
264269
}
265270
continue
266271
} else {
@@ -394,7 +399,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
394399
} else {
395400
// generate foreign keys from defined association foreign keys
396401
for _, scopeFieldName := range associationForeignKeys {
397-
if foreignField := getForeignField(scopeFieldName, modelStruct.StructFields); foreignField != nil {
402+
if foreignField := getForeignField(scopeFieldName, allFields); foreignField != nil {
398403
foreignKeys = append(foreignKeys, associationType+foreignField.Name)
399404
associationForeignKeys = append(associationForeignKeys, foreignField.Name)
400405
}
@@ -406,13 +411,13 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
406411
for _, foreignKey := range foreignKeys {
407412
if strings.HasPrefix(foreignKey, associationType) {
408413
associationForeignKey := strings.TrimPrefix(foreignKey, associationType)
409-
if foreignField := getForeignField(associationForeignKey, modelStruct.StructFields); foreignField != nil {
414+
if foreignField := getForeignField(associationForeignKey, allFields); foreignField != nil {
410415
associationForeignKeys = append(associationForeignKeys, associationForeignKey)
411416
}
412417
}
413418
}
414419
if len(associationForeignKeys) == 0 && len(foreignKeys) == 1 {
415-
associationForeignKeys = []string{scope.PrimaryKey()}
420+
associationForeignKeys = []string{rootScope.PrimaryKey()}
416421
}
417422
} else if len(foreignKeys) != len(associationForeignKeys) {
418423
scope.Err(errors.New("invalid foreign keys, should have same length"))
@@ -422,7 +427,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
422427

423428
for idx, foreignKey := range foreignKeys {
424429
if foreignField := getForeignField(foreignKey, toFields); foreignField != nil {
425-
if associationField := getForeignField(associationForeignKeys[idx], modelStruct.StructFields); associationField != nil {
430+
if associationField := getForeignField(associationForeignKeys[idx], allFields); associationField != nil {
426431
// mark field as foreignkey, use global lock to avoid race
427432
structsLock.Lock()
428433
foreignField.IsForeignKey = true
@@ -502,7 +507,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
502507
} else {
503508
// generate foreign keys form association foreign keys
504509
for _, associationForeignKey := range tagAssociationForeignKeys {
505-
if foreignField := getForeignField(associationForeignKey, modelStruct.StructFields); foreignField != nil {
510+
if foreignField := getForeignField(associationForeignKey, allFields); foreignField != nil {
506511
foreignKeys = append(foreignKeys, associationType+foreignField.Name)
507512
associationForeignKeys = append(associationForeignKeys, foreignField.Name)
508513
}
@@ -514,13 +519,13 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
514519
for _, foreignKey := range foreignKeys {
515520
if strings.HasPrefix(foreignKey, associationType) {
516521
associationForeignKey := strings.TrimPrefix(foreignKey, associationType)
517-
if foreignField := getForeignField(associationForeignKey, modelStruct.StructFields); foreignField != nil {
522+
if foreignField := getForeignField(associationForeignKey, allFields); foreignField != nil {
518523
associationForeignKeys = append(associationForeignKeys, associationForeignKey)
519524
}
520525
}
521526
}
522527
if len(associationForeignKeys) == 0 && len(foreignKeys) == 1 {
523-
associationForeignKeys = []string{scope.PrimaryKey()}
528+
associationForeignKeys = []string{rootScope.PrimaryKey()}
524529
}
525530
} else if len(foreignKeys) != len(associationForeignKeys) {
526531
scope.Err(errors.New("invalid foreign keys, should have same length"))
@@ -530,7 +535,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
530535

531536
for idx, foreignKey := range foreignKeys {
532537
if foreignField := getForeignField(foreignKey, toFields); foreignField != nil {
533-
if scopeField := getForeignField(associationForeignKeys[idx], modelStruct.StructFields); scopeField != nil {
538+
if scopeField := getForeignField(associationForeignKeys[idx], allFields); scopeField != nil {
534539
// mark field as foreignkey, use global lock to avoid race
535540
structsLock.Lock()
536541
foreignField.IsForeignKey = true
@@ -630,6 +635,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
630635
}
631636

632637
modelStruct.StructFields = append(modelStruct.StructFields, field)
638+
allFields = append(allFields, field)
633639
}
634640
}
635641

‎model_struct_test.go

+47
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,22 @@ type ModelC struct {
3131
OtherB *ModelB `gorm:"foreignkey:OtherBID"`
3232
}
3333

34+
type RequestModel struct {
35+
Name string
36+
Children []ChildModel `gorm:"foreignkey:ParentID"`
37+
}
38+
39+
type ChildModel struct {
40+
ID string
41+
ParentID string
42+
Name string
43+
}
44+
45+
type ResponseModel struct {
46+
gorm.Model
47+
RequestModel
48+
}
49+
3450
// This test will try to cause a race condition on the model's foreignkey metadata
3551
func TestModelStructRaceSameModel(t *testing.T) {
3652
// use a WaitGroup to execute as much in-sync as possible
@@ -91,3 +107,34 @@ func TestModelStructRaceDifferentModel(t *testing.T) {
91107

92108
done.Wait()
93109
}
110+
111+
func TestModelStructEmbeddedHasMany(t *testing.T) {
112+
fields := DB.NewScope(&ResponseModel{}).GetStructFields()
113+
114+
var childrenField *gorm.StructField
115+
116+
for i := 0; i < len(fields); i++ {
117+
field := fields[i]
118+
119+
if field != nil && field.Name == "Children" {
120+
childrenField = field
121+
}
122+
}
123+
124+
if childrenField == nil {
125+
t.Error("childrenField should not be nil")
126+
return
127+
}
128+
129+
if childrenField.Relationship == nil {
130+
t.Error("childrenField.Relation should not be nil")
131+
return
132+
}
133+
134+
expected := "has_many"
135+
actual := childrenField.Relationship.Kind
136+
137+
if actual != expected {
138+
t.Errorf("childrenField.Relationship.Kind should be %v, but was %v", expected, actual)
139+
}
140+
}

0 commit comments

Comments
 (0)
Please sign in to comment.