Fix create foreign keys for many2many relations
This commit is contained in:
		
							parent
							
								
									5883490aa7
								
							
						
					
					
						commit
						fee1e4aafd
					
				
							
								
								
									
										7
									
								
								gorm.go
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								gorm.go
									
									
									
									
									
								
							| @ -293,6 +293,13 @@ func (db *DB) SetupJoinTable(model interface{}, field string, joinTable interfac | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		for name, rel := range relation.JoinTable.Relationships.Relations { | ||||||
|  | 			if _, ok := joinSchema.Relationships.Relations[name]; !ok { | ||||||
|  | 				rel.Schema = joinSchema | ||||||
|  | 				joinSchema.Relationships.Relations[name] = rel | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		relation.JoinTable = joinSchema | 		relation.JoinTable = joinSchema | ||||||
| 	} else { | 	} else { | ||||||
| 		return fmt.Errorf("failed to found relation: %v", field) | 		return fmt.Errorf("failed to found relation: %v", field) | ||||||
|  | |||||||
| @ -88,7 +88,7 @@ func (m Migrator) AutoMigrate(values ...interface{}) error { | |||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 		} else { | 		} else { | ||||||
| 			if err := m.RunWithValue(value, func(stmt *gorm.Statement) error { | 			if err := m.RunWithValue(value, func(stmt *gorm.Statement) (errr error) { | ||||||
| 				for _, field := range stmt.Schema.FieldsByDBName { | 				for _, field := range stmt.Schema.FieldsByDBName { | ||||||
| 					if !tx.Migrator().HasColumn(value, field.DBName) { | 					if !tx.Migrator().HasColumn(value, field.DBName) { | ||||||
| 						if err := tx.Migrator().AddColumn(value, field.DBName); err != nil { | 						if err := tx.Migrator().AddColumn(value, field.DBName); err != nil { | ||||||
| @ -120,9 +120,13 @@ func (m Migrator) AutoMigrate(values ...interface{}) error { | |||||||
| 					if rel.JoinTable != nil { | 					if rel.JoinTable != nil { | ||||||
| 						joinValue := reflect.New(rel.JoinTable.ModelType).Interface() | 						joinValue := reflect.New(rel.JoinTable.ModelType).Interface() | ||||||
| 						if !tx.Migrator().HasTable(rel.JoinTable.Table) { | 						if !tx.Migrator().HasTable(rel.JoinTable.Table) { | ||||||
| 							defer tx.Table(rel.JoinTable.Table).Migrator().CreateTable(joinValue) | 							defer func() { | ||||||
|  | 								errr = tx.Table(rel.JoinTable.Table).Migrator().CreateTable(joinValue) | ||||||
|  | 							}() | ||||||
| 						} else { | 						} else { | ||||||
| 							defer tx.Table(rel.JoinTable.Table).Migrator().AutoMigrate(joinValue) | 							defer func() { | ||||||
|  | 								errr = tx.Table(rel.JoinTable.Table).Migrator().AutoMigrate(joinValue) | ||||||
|  | 							}() | ||||||
| 						} | 						} | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| @ -139,7 +143,7 @@ func (m Migrator) AutoMigrate(values ...interface{}) error { | |||||||
| func (m Migrator) CreateTable(values ...interface{}) error { | func (m Migrator) CreateTable(values ...interface{}) error { | ||||||
| 	for _, value := range m.ReorderModels(values, false) { | 	for _, value := range m.ReorderModels(values, false) { | ||||||
| 		tx := m.DB.Session(&gorm.Session{}) | 		tx := m.DB.Session(&gorm.Session{}) | ||||||
| 		if err := m.RunWithValue(value, func(stmt *gorm.Statement) error { | 		if err := m.RunWithValue(value, func(stmt *gorm.Statement) (errr error) { | ||||||
| 			var ( | 			var ( | ||||||
| 				createTableSQL          = "CREATE TABLE ? (" | 				createTableSQL          = "CREATE TABLE ? (" | ||||||
| 				values                  = []interface{}{clause.Table{Name: stmt.Table}} | 				values                  = []interface{}{clause.Table{Name: stmt.Table}} | ||||||
| @ -166,7 +170,9 @@ func (m Migrator) CreateTable(values ...interface{}) error { | |||||||
| 
 | 
 | ||||||
| 			for _, idx := range stmt.Schema.ParseIndexes() { | 			for _, idx := range stmt.Schema.ParseIndexes() { | ||||||
| 				if m.CreateIndexAfterCreateTable { | 				if m.CreateIndexAfterCreateTable { | ||||||
| 					defer tx.Migrator().CreateIndex(value, idx.Name) | 					defer func() { | ||||||
|  | 						errr = tx.Migrator().CreateIndex(value, idx.Name) | ||||||
|  | 					}() | ||||||
| 				} else { | 				} else { | ||||||
| 					createTableSQL += "INDEX ? ?," | 					createTableSQL += "INDEX ? ?," | ||||||
| 					values = append(values, clause.Expr{SQL: idx.Name}, tx.Migrator().(BuildIndexOptionsInterface).BuildIndexOptions(idx.Fields, stmt)) | 					values = append(values, clause.Expr{SQL: idx.Name}, tx.Migrator().(BuildIndexOptionsInterface).BuildIndexOptions(idx.Fields, stmt)) | ||||||
| @ -186,7 +192,9 @@ func (m Migrator) CreateTable(values ...interface{}) error { | |||||||
| 				if rel.JoinTable != nil { | 				if rel.JoinTable != nil { | ||||||
| 					joinValue := reflect.New(rel.JoinTable.ModelType).Interface() | 					joinValue := reflect.New(rel.JoinTable.ModelType).Interface() | ||||||
| 					if !tx.Migrator().HasTable(rel.JoinTable.Table) { | 					if !tx.Migrator().HasTable(rel.JoinTable.Table) { | ||||||
| 						defer tx.Table(rel.JoinTable.Table).Migrator().CreateTable(joinValue) | 						defer func(table string, joinValue interface{}) { | ||||||
|  | 							errr = tx.Table(table).Migrator().CreateTable(joinValue) | ||||||
|  | 						}(rel.JoinTable.Table, joinValue) | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| @ -204,7 +212,8 @@ func (m Migrator) CreateTable(values ...interface{}) error { | |||||||
| 				createTableSQL += fmt.Sprint(tableOption) | 				createTableSQL += fmt.Sprint(tableOption) | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			return tx.Exec(createTableSQL, values...).Error | 			errr = tx.Exec(createTableSQL, values...).Error | ||||||
|  | 			return errr | ||||||
| 		}); err != nil { | 		}); err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| @ -553,6 +562,10 @@ func (m Migrator) ReorderModels(values []interface{}, autoAdd bool) (results []i | |||||||
| 			if c := rel.ParseConstraint(); c != nil && c.Schema == dep.Statement.Schema && c.Schema != c.ReferenceSchema { | 			if c := rel.ParseConstraint(); c != nil && c.Schema == dep.Statement.Schema && c.Schema != c.ReferenceSchema { | ||||||
| 				dep.Depends = append(dep.Depends, c.ReferenceSchema) | 				dep.Depends = append(dep.Depends, c.ReferenceSchema) | ||||||
| 			} | 			} | ||||||
|  | 
 | ||||||
|  | 			if rel.JoinTable != nil && rel.Schema != rel.FieldSchema { | ||||||
|  | 				dep.Depends = append(dep.Depends, rel.FieldSchema) | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		valuesMap[dep.Schema.Table] = dep | 		valuesMap[dep.Schema.Table] = dep | ||||||
| @ -566,6 +579,7 @@ func (m Migrator) ReorderModels(values []interface{}, autoAdd bool) (results []i | |||||||
| 		if _, ok := orderedModelNamesMap[name]; ok { | 		if _, ok := orderedModelNamesMap[name]; ok { | ||||||
| 			return // avoid loop
 | 			return // avoid loop
 | ||||||
| 		} | 		} | ||||||
|  | 		orderedModelNamesMap[name] = true | ||||||
| 
 | 
 | ||||||
| 		dep := valuesMap[name] | 		dep := valuesMap[name] | ||||||
| 		for _, d := range dep.Depends { | 		for _, d := range dep.Depends { | ||||||
| @ -578,7 +592,6 @@ func (m Migrator) ReorderModels(values []interface{}, autoAdd bool) (results []i | |||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		orderedModelNames = append(orderedModelNames, name) | 		orderedModelNames = append(orderedModelNames, name) | ||||||
| 		orderedModelNamesMap[name] = true |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	for _, value := range values { | 	for _, value := range values { | ||||||
|  | |||||||
| @ -46,7 +46,7 @@ func (ns NamingStrategy) JoinTableName(str string) string { | |||||||
| 
 | 
 | ||||||
| // RelationshipFKName generate fk name for relation
 | // RelationshipFKName generate fk name for relation
 | ||||||
| func (ns NamingStrategy) RelationshipFKName(rel Relationship) string { | func (ns NamingStrategy) RelationshipFKName(rel Relationship) string { | ||||||
| 	return fmt.Sprintf("fk_%s_%s", rel.Schema.Table, toDBName(rel.Field.Name)) | 	return fmt.Sprintf("fk_%s_%s", rel.Schema.Table, toDBName(rel.Name)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // CheckerName generate checker name
 | // CheckerName generate checker name
 | ||||||
|  | |||||||
| @ -253,16 +253,63 @@ func (schema *Schema) buildMany2ManyRelation(relation *Relationship, field *Fiel | |||||||
| 	relation.JoinTable.Table = schema.namer.JoinTableName(many2many) | 	relation.JoinTable.Table = schema.namer.JoinTableName(many2many) | ||||||
| 	relation.JoinTable.PrimaryFields = make([]*Field, len(relation.JoinTable.Fields)) | 	relation.JoinTable.PrimaryFields = make([]*Field, len(relation.JoinTable.Fields)) | ||||||
| 
 | 
 | ||||||
|  | 	relName := relation.Schema.Name | ||||||
|  | 	relRefName := relation.FieldSchema.Name | ||||||
|  | 	if relName == relRefName { | ||||||
|  | 		relRefName = relation.Field.Name | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if _, ok := relation.JoinTable.Relationships.Relations[relName]; !ok { | ||||||
|  | 		relation.JoinTable.Relationships.Relations[relName] = &Relationship{ | ||||||
|  | 			Name:        relName, | ||||||
|  | 			Type:        BelongsTo, | ||||||
|  | 			Schema:      relation.JoinTable, | ||||||
|  | 			FieldSchema: relation.Schema, | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		relation.JoinTable.Relationships.Relations[relName].References = []*Reference{} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if _, ok := relation.JoinTable.Relationships.Relations[relRefName]; !ok { | ||||||
|  | 		relation.JoinTable.Relationships.Relations[relRefName] = &Relationship{ | ||||||
|  | 			Name:        relRefName, | ||||||
|  | 			Type:        BelongsTo, | ||||||
|  | 			Schema:      relation.JoinTable, | ||||||
|  | 			FieldSchema: relation.FieldSchema, | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		relation.JoinTable.Relationships.Relations[relRefName].References = []*Reference{} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	// build references
 | 	// build references
 | ||||||
| 	for idx, f := range relation.JoinTable.Fields { | 	for idx, f := range relation.JoinTable.Fields { | ||||||
| 		// use same data type for foreign keys
 | 		// use same data type for foreign keys
 | ||||||
| 		f.DataType = fieldsMap[f.Name].DataType | 		f.DataType = fieldsMap[f.Name].DataType | ||||||
| 		relation.JoinTable.PrimaryFields[idx] = f | 		relation.JoinTable.PrimaryFields[idx] = 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 | ||||||
|  | 			} | ||||||
|  | 			joinRefRel.References = append(joinRefRel.References, &Reference{ | ||||||
|  | 				PrimaryKey: fieldsMap[f.Name], | ||||||
|  | 				ForeignKey: f, | ||||||
|  | 			}) | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		relation.References = append(relation.References, &Reference{ | 		relation.References = append(relation.References, &Reference{ | ||||||
| 			PrimaryKey:    fieldsMap[f.Name], | 			PrimaryKey:    fieldsMap[f.Name], | ||||||
| 			ForeignKey:    f, | 			ForeignKey:    f, | ||||||
| 			OwnPrimaryKey: schema == fieldsMap[f.Name].Schema && ownFieldsMap[f.Name], | 			OwnPrimaryKey: ownPriamryField, | ||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| 	return | 	return | ||||||
|  | |||||||
| @ -6,9 +6,9 @@ require ( | |||||||
| 	github.com/google/uuid v1.1.1 | 	github.com/google/uuid v1.1.1 | ||||||
| 	github.com/jinzhu/now v1.1.1 | 	github.com/jinzhu/now v1.1.1 | ||||||
| 	github.com/lib/pq v1.6.0 | 	github.com/lib/pq v1.6.0 | ||||||
| 	gorm.io/driver/mysql v0.2.2 | 	gorm.io/driver/mysql v0.2.3 | ||||||
| 	gorm.io/driver/postgres v0.2.2 | 	gorm.io/driver/postgres v0.2.2 | ||||||
| 	gorm.io/driver/sqlite v1.0.5 | 	gorm.io/driver/sqlite v1.0.6 | ||||||
| 	gorm.io/driver/sqlserver v0.2.2 | 	gorm.io/driver/sqlserver v0.2.2 | ||||||
| 	gorm.io/gorm v0.2.9 | 	gorm.io/gorm v0.2.9 | ||||||
| ) | ) | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Jinzhu
						Jinzhu