From 162367be7d1d10aa59dc08bb507c356b4495c95e Mon Sep 17 00:00:00 2001 From: Jinzhu Date: Tue, 1 Sep 2020 11:30:16 +0800 Subject: [PATCH] Fix multiple M2M relations on one table, close #3347 --- schema/relationship.go | 62 +++++++++++++++++++++---------------- schema/relationship_test.go | 31 +++++++++++++++++++ 2 files changed, 66 insertions(+), 27 deletions(-) diff --git a/schema/relationship.go b/schema/relationship.go index 5132ff74..aa992b84 100644 --- a/schema/relationship.go +++ b/schema/relationship.go @@ -254,12 +254,18 @@ func (schema *Schema) buildMany2ManyRelation(relation *Relationship, field *Fiel }) } + joinTableFields = append(joinTableFields, reflect.StructField{ + Name: schema.Name + field.Name, + Type: schema.ModelType, + Tag: `gorm:"-"`, + }) + if relation.JoinTable, err = Parse(reflect.New(reflect.StructOf(joinTableFields)).Interface(), schema.cacheStore, schema.namer); err != nil { schema.err = err } relation.JoinTable.Name = many2many relation.JoinTable.Table = schema.namer.JoinTableName(many2many) - relation.JoinTable.PrimaryFields = make([]*Field, len(relation.JoinTable.Fields)) + relation.JoinTable.PrimaryFields = make([]*Field, 0, len(relation.JoinTable.Fields)) relName := relation.Schema.Name relRefName := relation.FieldSchema.Name @@ -290,36 +296,38 @@ func (schema *Schema) buildMany2ManyRelation(relation *Relationship, field *Fiel } // build references - for idx, f := range relation.JoinTable.Fields { - // use same data type for foreign keys - f.DataType = fieldsMap[f.Name].DataType - f.GORMDataType = fieldsMap[f.Name].GORMDataType - relation.JoinTable.PrimaryFields[idx] = f - ownPriamryField := schema == fieldsMap[f.Name].Schema && ownFieldsMap[f.Name] + for _, f := range relation.JoinTable.Fields { + if f.Creatable { + // use same data type for foreign keys + f.DataType = fieldsMap[f.Name].DataType + f.GORMDataType = fieldsMap[f.Name].GORMDataType + relation.JoinTable.PrimaryFields = append(relation.JoinTable.PrimaryFields, f) + ownPriamryField := schema == fieldsMap[f.Name].Schema && ownFieldsMap[f.Name] - if ownPriamryField { - joinRel := relation.JoinTable.Relationships.Relations[relName] - joinRel.Field = relation.Field - joinRel.References = append(joinRel.References, &Reference{ - PrimaryKey: fieldsMap[f.Name], - ForeignKey: f, - }) - } else { - joinRefRel := relation.JoinTable.Relationships.Relations[relRefName] - if joinRefRel.Field == nil { - joinRefRel.Field = relation.Field + if ownPriamryField { + joinRel := relation.JoinTable.Relationships.Relations[relName] + joinRel.Field = relation.Field + joinRel.References = append(joinRel.References, &Reference{ + PrimaryKey: fieldsMap[f.Name], + ForeignKey: f, + }) + } else { + joinRefRel := relation.JoinTable.Relationships.Relations[relRefName] + if joinRefRel.Field == nil { + joinRefRel.Field = relation.Field + } + joinRefRel.References = append(joinRefRel.References, &Reference{ + PrimaryKey: fieldsMap[f.Name], + ForeignKey: f, + }) } - joinRefRel.References = append(joinRefRel.References, &Reference{ - PrimaryKey: fieldsMap[f.Name], - ForeignKey: f, + + relation.References = append(relation.References, &Reference{ + PrimaryKey: fieldsMap[f.Name], + ForeignKey: f, + OwnPrimaryKey: ownPriamryField, }) } - - relation.References = append(relation.References, &Reference{ - PrimaryKey: fieldsMap[f.Name], - ForeignKey: f, - OwnPrimaryKey: ownPriamryField, - }) } } diff --git a/schema/relationship_test.go b/schema/relationship_test.go index 2e85c538..f2d63323 100644 --- a/schema/relationship_test.go +++ b/schema/relationship_test.go @@ -267,3 +267,34 @@ func TestMany2ManyWithMultiPrimaryKeys(t *testing.T) { }, ) } + +func TestMultipleMany2Many(t *testing.T) { + type Thing struct { + ID int + } + + type Person struct { + ID int + Likes []Thing `gorm:"many2many:likes"` + Dislikes []Thing `gorm:"many2many:dislikes"` + } + + checkStructRelation(t, &Person{}, + Relation{ + Name: "Likes", Type: schema.Many2Many, Schema: "Person", FieldSchema: "Thing", + JoinTable: JoinTable{Name: "likes", Table: "likes"}, + References: []Reference{ + {"ID", "Person", "PersonID", "likes", "", true}, + {"ID", "Thing", "ThingID", "likes", "", false}, + }, + }, + Relation{ + Name: "Dislikes", Type: schema.Many2Many, Schema: "Person", FieldSchema: "Thing", + JoinTable: JoinTable{Name: "dislikes", Table: "dislikes"}, + References: []Reference{ + {"ID", "Person", "PersonID", "dislikes", "", true}, + {"ID", "Thing", "ThingID", "dislikes", "", false}, + }, + }, + ) +}