mirror of https://github.com/go-gorm/gorm.git
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…
Reference in New Issue