forked from mirror/gorm
Allow shared foreign key for many2many jointable
This commit is contained in:
parent
1f634c3937
commit
3a72ba102e
|
@ -191,7 +191,8 @@ func (schema *Schema) buildMany2ManyRelation(relation *Relationship, field *Fiel
|
||||||
err error
|
err error
|
||||||
joinTableFields []reflect.StructField
|
joinTableFields []reflect.StructField
|
||||||
fieldsMap = map[string]*Field{}
|
fieldsMap = map[string]*Field{}
|
||||||
ownFieldsMap = map[string]bool{} // fix self join many2many
|
ownFieldsMap = map[string]*Field{} // fix self join many2many
|
||||||
|
referFieldsMap = map[string]*Field{}
|
||||||
joinForeignKeys = toColumns(field.TagSettings["JOINFOREIGNKEY"])
|
joinForeignKeys = toColumns(field.TagSettings["JOINFOREIGNKEY"])
|
||||||
joinReferences = toColumns(field.TagSettings["JOINREFERENCES"])
|
joinReferences = toColumns(field.TagSettings["JOINREFERENCES"])
|
||||||
)
|
)
|
||||||
|
@ -229,7 +230,7 @@ func (schema *Schema) buildMany2ManyRelation(relation *Relationship, field *Fiel
|
||||||
joinFieldName = strings.Title(joinForeignKeys[idx])
|
joinFieldName = strings.Title(joinForeignKeys[idx])
|
||||||
}
|
}
|
||||||
|
|
||||||
ownFieldsMap[joinFieldName] = true
|
ownFieldsMap[joinFieldName] = ownField
|
||||||
fieldsMap[joinFieldName] = ownField
|
fieldsMap[joinFieldName] = ownField
|
||||||
joinTableFields = append(joinTableFields, reflect.StructField{
|
joinTableFields = append(joinTableFields, reflect.StructField{
|
||||||
Name: joinFieldName,
|
Name: joinFieldName,
|
||||||
|
@ -242,9 +243,6 @@ func (schema *Schema) buildMany2ManyRelation(relation *Relationship, field *Fiel
|
||||||
|
|
||||||
for idx, relField := range refForeignFields {
|
for idx, relField := range refForeignFields {
|
||||||
joinFieldName := strings.Title(relation.FieldSchema.Name) + relField.Name
|
joinFieldName := strings.Title(relation.FieldSchema.Name) + relField.Name
|
||||||
if len(joinReferences) > idx {
|
|
||||||
joinFieldName = strings.Title(joinReferences[idx])
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := ownFieldsMap[joinFieldName]; ok {
|
if _, ok := ownFieldsMap[joinFieldName]; ok {
|
||||||
if field.Name != relation.FieldSchema.Name {
|
if field.Name != relation.FieldSchema.Name {
|
||||||
|
@ -254,14 +252,22 @@ func (schema *Schema) buildMany2ManyRelation(relation *Relationship, field *Fiel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldsMap[joinFieldName] = relField
|
if len(joinReferences) > idx {
|
||||||
joinTableFields = append(joinTableFields, reflect.StructField{
|
joinFieldName = strings.Title(joinReferences[idx])
|
||||||
Name: joinFieldName,
|
}
|
||||||
PkgPath: relField.StructField.PkgPath,
|
|
||||||
Type: relField.StructField.Type,
|
referFieldsMap[joinFieldName] = relField
|
||||||
Tag: removeSettingFromTag(appendSettingFromTag(relField.StructField.Tag, "primaryKey"),
|
|
||||||
"column", "autoincrement", "index", "unique", "uniqueindex"),
|
if _, ok := fieldsMap[joinFieldName]; !ok {
|
||||||
})
|
fieldsMap[joinFieldName] = relField
|
||||||
|
joinTableFields = append(joinTableFields, reflect.StructField{
|
||||||
|
Name: joinFieldName,
|
||||||
|
PkgPath: relField.StructField.PkgPath,
|
||||||
|
Type: relField.StructField.Type,
|
||||||
|
Tag: removeSettingFromTag(appendSettingFromTag(relField.StructField.Tag, "primaryKey"),
|
||||||
|
"column", "autoincrement", "index", "unique", "uniqueindex"),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
joinTableFields = append(joinTableFields, reflect.StructField{
|
joinTableFields = append(joinTableFields, reflect.StructField{
|
||||||
|
@ -317,31 +323,37 @@ func (schema *Schema) buildMany2ManyRelation(relation *Relationship, field *Fiel
|
||||||
f.Size = fieldsMap[f.Name].Size
|
f.Size = fieldsMap[f.Name].Size
|
||||||
}
|
}
|
||||||
relation.JoinTable.PrimaryFields = append(relation.JoinTable.PrimaryFields, f)
|
relation.JoinTable.PrimaryFields = append(relation.JoinTable.PrimaryFields, f)
|
||||||
ownPrimaryField := schema == fieldsMap[f.Name].Schema && ownFieldsMap[f.Name]
|
|
||||||
|
|
||||||
if ownPrimaryField {
|
if of, ok := ownFieldsMap[f.Name]; ok {
|
||||||
joinRel := relation.JoinTable.Relationships.Relations[relName]
|
joinRel := relation.JoinTable.Relationships.Relations[relName]
|
||||||
joinRel.Field = relation.Field
|
joinRel.Field = relation.Field
|
||||||
joinRel.References = append(joinRel.References, &Reference{
|
joinRel.References = append(joinRel.References, &Reference{
|
||||||
PrimaryKey: fieldsMap[f.Name],
|
PrimaryKey: of,
|
||||||
ForeignKey: f,
|
ForeignKey: f,
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
|
relation.References = append(relation.References, &Reference{
|
||||||
|
PrimaryKey: of,
|
||||||
|
ForeignKey: f,
|
||||||
|
OwnPrimaryKey: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if rf, ok := referFieldsMap[f.Name]; ok {
|
||||||
joinRefRel := relation.JoinTable.Relationships.Relations[relRefName]
|
joinRefRel := relation.JoinTable.Relationships.Relations[relRefName]
|
||||||
if joinRefRel.Field == nil {
|
if joinRefRel.Field == nil {
|
||||||
joinRefRel.Field = relation.Field
|
joinRefRel.Field = relation.Field
|
||||||
}
|
}
|
||||||
joinRefRel.References = append(joinRefRel.References, &Reference{
|
joinRefRel.References = append(joinRefRel.References, &Reference{
|
||||||
PrimaryKey: fieldsMap[f.Name],
|
PrimaryKey: rf,
|
||||||
|
ForeignKey: f,
|
||||||
|
})
|
||||||
|
|
||||||
|
relation.References = append(relation.References, &Reference{
|
||||||
|
PrimaryKey: rf,
|
||||||
ForeignKey: f,
|
ForeignKey: f,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
relation.References = append(relation.References, &Reference{
|
|
||||||
PrimaryKey: fieldsMap[f.Name],
|
|
||||||
ForeignKey: f,
|
|
||||||
OwnPrimaryKey: ownPrimaryField,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
|
|
||||||
func checkStructRelation(t *testing.T, data interface{}, relations ...Relation) {
|
func checkStructRelation(t *testing.T, data interface{}, relations ...Relation) {
|
||||||
if s, err := schema.Parse(data, &sync.Map{}, schema.NamingStrategy{}); err != nil {
|
if s, err := schema.Parse(data, &sync.Map{}, schema.NamingStrategy{}); err != nil {
|
||||||
t.Errorf("Failed to parse schema")
|
t.Errorf("Failed to parse schema, got error %v", err)
|
||||||
} else {
|
} else {
|
||||||
for _, rel := range relations {
|
for _, rel := range relations {
|
||||||
checkSchemaRelation(t, s, rel)
|
checkSchemaRelation(t, s, rel)
|
||||||
|
@ -305,6 +305,33 @@ func TestMany2ManyOverrideForeignKey(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMany2ManySharedForeignKey(t *testing.T) {
|
||||||
|
type Profile struct {
|
||||||
|
gorm.Model
|
||||||
|
Name string
|
||||||
|
Kind string
|
||||||
|
ProfileRefer uint
|
||||||
|
}
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
gorm.Model
|
||||||
|
Profiles []Profile `gorm:"many2many:user_profiles;foreignKey:Refer,Kind;joinForeignKey:UserRefer,Kind;References:ProfileRefer,Kind;joinReferences:ProfileR,Kind"`
|
||||||
|
Kind string
|
||||||
|
Refer uint
|
||||||
|
}
|
||||||
|
|
||||||
|
checkStructRelation(t, &User{}, Relation{
|
||||||
|
Name: "Profiles", Type: schema.Many2Many, Schema: "User", FieldSchema: "Profile",
|
||||||
|
JoinTable: JoinTable{Name: "user_profiles", Table: "user_profiles"},
|
||||||
|
References: []Reference{
|
||||||
|
{"Refer", "User", "UserRefer", "user_profiles", "", true},
|
||||||
|
{"Kind", "User", "Kind", "user_profiles", "", true},
|
||||||
|
{"ProfileRefer", "Profile", "ProfileR", "user_profiles", "", false},
|
||||||
|
{"Kind", "Profile", "Kind", "user_profiles", "", false},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestMany2ManyOverrideJoinForeignKey(t *testing.T) {
|
func TestMany2ManyOverrideJoinForeignKey(t *testing.T) {
|
||||||
type Profile struct {
|
type Profile struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
|
|
13
tests/go.mod
13
tests/go.mod
|
@ -3,17 +3,18 @@ module gorm.io/gorm/tests
|
||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/denisenkom/go-mssqldb v0.12.2 // indirect
|
||||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/jinzhu/now v1.1.5
|
github.com/jinzhu/now v1.1.5
|
||||||
github.com/lib/pq v1.10.6
|
github.com/lib/pq v1.10.7
|
||||||
github.com/mattn/go-sqlite3 v1.14.14 // indirect
|
github.com/mattn/go-sqlite3 v1.14.15 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
|
golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 // indirect
|
||||||
gorm.io/driver/mysql v1.3.5
|
gorm.io/driver/mysql v1.3.6
|
||||||
gorm.io/driver/postgres v1.3.8
|
gorm.io/driver/postgres v1.3.10
|
||||||
gorm.io/driver/sqlite v1.3.6
|
gorm.io/driver/sqlite v1.3.6
|
||||||
gorm.io/driver/sqlserver v1.3.2
|
gorm.io/driver/sqlserver v1.3.2
|
||||||
gorm.io/gorm v1.23.8
|
gorm.io/gorm v1.23.9
|
||||||
)
|
)
|
||||||
|
|
||||||
replace gorm.io/gorm => ../
|
replace gorm.io/gorm => ../
|
||||||
|
|
Loading…
Reference in New Issue