Use JoinTable instead of ForeignKey
This commit is contained in:
parent
d7400c2df4
commit
a7aaf151cf
@ -1,6 +1,9 @@
|
|||||||
package gorm
|
package gorm
|
||||||
|
|
||||||
import "reflect"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
func BeginTransaction(scope *Scope) {
|
func BeginTransaction(scope *Scope) {
|
||||||
scope.Begin()
|
scope.Begin()
|
||||||
@ -28,8 +31,8 @@ func SaveBeforeAssociations(scope *Scope) {
|
|||||||
scope.SetColumn(field.Name, value.Interface())
|
scope.SetColumn(field.Name, value.Interface())
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(field.ForeignKey) > 0 {
|
if field.JoinTable != nil && field.JoinTable.foreignKey != "" {
|
||||||
scope.SetColumn(field.ForeignKey, newDB.NewScope(value.Interface()).PrimaryKeyValue())
|
scope.SetColumn(field.JoinTable.foreignKey, newDB.NewScope(value.Interface()).PrimaryKeyValue())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,16 +49,19 @@ func SaveAfterAssociations(scope *Scope) {
|
|||||||
newDB := scope.NewDB()
|
newDB := scope.NewDB()
|
||||||
elem := value.Index(i).Addr().Interface()
|
elem := value.Index(i).Addr().Interface()
|
||||||
|
|
||||||
if len(field.ForeignKey) > 0 {
|
if field.JoinTable != nil && field.JoinTable.foreignKey != "" {
|
||||||
newDB.NewScope(elem).SetColumn(field.ForeignKey, scope.PrimaryKeyValue())
|
newDB.NewScope(elem).SetColumn(field.JoinTable.foreignKey, scope.PrimaryKeyValue())
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.Err(newDB.Save(elem).Error)
|
scope.Err(newDB.Save(elem).Error)
|
||||||
|
fmt.Sprintf("INSERT INTO %v (%v, %v) SELECT (%v, %v) FROM %v WHERE NOT EXISTS (SELECT * FROM %v WHERE %v = %v AND %v = %v) limit 1;")
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
newDB := scope.NewDB()
|
newDB := scope.NewDB()
|
||||||
if value.CanAddr() {
|
if value.CanAddr() {
|
||||||
newDB.NewScope(field.Value).SetColumn(field.ForeignKey, scope.PrimaryKeyValue())
|
if field.JoinTable != nil {
|
||||||
|
newDB.NewScope(field.Value).SetColumn(field.JoinTable.foreignKey, scope.PrimaryKeyValue())
|
||||||
|
}
|
||||||
scope.Err(newDB.Save(field.Value).Error)
|
scope.Err(newDB.Save(field.Value).Error)
|
||||||
} else {
|
} else {
|
||||||
destValue := reflect.New(reflect.TypeOf(field.Value)).Elem()
|
destValue := reflect.New(reflect.TypeOf(field.Value)).Elem()
|
||||||
@ -65,7 +71,9 @@ func SaveAfterAssociations(scope *Scope) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
elem := destValue.Addr().Interface()
|
elem := destValue.Addr().Interface()
|
||||||
newDB.NewScope(elem).SetColumn(field.ForeignKey, scope.PrimaryKeyValue())
|
if field.JoinTable != nil {
|
||||||
|
newDB.NewScope(elem).SetColumn(field.JoinTable.foreignKey, scope.PrimaryKeyValue())
|
||||||
|
}
|
||||||
scope.Err(newDB.Save(elem).Error)
|
scope.Err(newDB.Save(elem).Error)
|
||||||
scope.SetColumn(field.Name, destValue.Interface())
|
scope.SetColumn(field.Name, destValue.Interface())
|
||||||
}
|
}
|
||||||
|
8
field.go
8
field.go
@ -6,6 +6,12 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type joinTable struct {
|
||||||
|
joinTable string
|
||||||
|
foreignKey string
|
||||||
|
associationForeignKey string
|
||||||
|
}
|
||||||
|
|
||||||
type Field struct {
|
type Field struct {
|
||||||
Name string
|
Name string
|
||||||
DBName string
|
DBName string
|
||||||
@ -14,10 +20,10 @@ type Field struct {
|
|||||||
IsIgnored bool
|
IsIgnored bool
|
||||||
Tag reflect.StructTag
|
Tag reflect.StructTag
|
||||||
SqlTag string
|
SqlTag string
|
||||||
ForeignKey string
|
|
||||||
BeforeAssociation bool
|
BeforeAssociation bool
|
||||||
AfterAssociation bool
|
AfterAssociation bool
|
||||||
isPrimaryKey bool
|
isPrimaryKey bool
|
||||||
|
JoinTable *joinTable
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Field) IsScanner() bool {
|
func (f *Field) IsScanner() bool {
|
||||||
|
@ -115,8 +115,8 @@ func TestRelated(t *testing.T) {
|
|||||||
|
|
||||||
var creditcard CreditCard
|
var creditcard CreditCard
|
||||||
var user3 User
|
var user3 User
|
||||||
db.First(&creditcard, "number = ?", "1234567890")
|
db.Debug().First(&creditcard, "number = ?", "1234567890")
|
||||||
db.Model(&creditcard).Related(&user3)
|
db.Debug().Model(&creditcard).Related(&user3)
|
||||||
if user3.Id != user.Id || user3.Name != user.Name {
|
if user3.Id != user.Id || user3.Name != user.Name {
|
||||||
t.Errorf("Should get user from credit card correctly")
|
t.Errorf("Should get user from credit card correctly")
|
||||||
}
|
}
|
||||||
@ -131,17 +131,17 @@ func TestQueryManyToManyWithRelated(t *testing.T) {
|
|||||||
user := User{Name: "Many2Many", Languages: languages}
|
user := User{Name: "Many2Many", Languages: languages}
|
||||||
db.Save(&user)
|
db.Save(&user)
|
||||||
|
|
||||||
// var newLanguages []Language
|
var newLanguages []Language
|
||||||
// db.Model(&user).Related(&newLanguages, "Languages")
|
// db.Model(&user).Related(&newLanguages, "Languages")
|
||||||
// if len(newLanguages) != 3 {
|
// if len(newLanguages) != 3 {
|
||||||
// t.Errorf("Query many to many relations")
|
// t.Errorf("Query many to many relations")
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// newLanguages = []Language{}
|
newLanguages = []Language{}
|
||||||
// db.Model(&user).Many2Many("Languages").Find(&newLanguages)
|
db.Model(&user).Many2Many("Languages").Find(&newLanguages)
|
||||||
// if len(newLanguages) != 3 {
|
if len(newLanguages) != 3 {
|
||||||
// t.Errorf("Query many to many relations")
|
t.Errorf("Query many to many relations")
|
||||||
// }
|
}
|
||||||
|
|
||||||
// db.Model(&User{}).Many2Many("Languages").Add(&Language{})
|
// db.Model(&User{}).Many2Many("Languages").Add(&Language{})
|
||||||
// db.Model(&User{}).Many2Many("Languages").Remove(&Language{})
|
// db.Model(&User{}).Many2Many("Languages").Remove(&Language{})
|
||||||
|
43
scope.go
43
scope.go
@ -263,33 +263,56 @@ func (scope *Scope) Fields() []*Field {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if scope.db != nil {
|
if scope.db != nil {
|
||||||
|
indirectValue := reflect.Indirect(value)
|
||||||
field.Tag = fieldStruct.Tag
|
field.Tag = fieldStruct.Tag
|
||||||
field.SqlTag = scope.sqlTagForField(&field)
|
field.SqlTag = scope.sqlTagForField(&field)
|
||||||
|
|
||||||
// parse association
|
// parse association
|
||||||
elem := reflect.Indirect(value)
|
typ := indirectValue.Type()
|
||||||
typ := elem.Type()
|
foreignKey := settings["FOREIGNKEY"]
|
||||||
|
associationForeignKey := settings["ASSOCIATIONFOREIGNKEY"]
|
||||||
|
many2many := settings["MANY2MANY"]
|
||||||
|
|
||||||
switch elem.Kind() {
|
switch indirectValue.Kind() {
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
typ = typ.Elem()
|
typ = typ.Elem()
|
||||||
|
|
||||||
if typ.Kind() == reflect.Struct {
|
if typ.Kind() == reflect.Struct {
|
||||||
foreignKey := scopeTyp.Name() + "Id"
|
if foreignKey == "" {
|
||||||
if reflect.New(typ).Elem().FieldByName(foreignKey).IsValid() {
|
foreignKey = scopeTyp.Name() + "Id"
|
||||||
field.ForeignKey = foreignKey
|
|
||||||
}
|
}
|
||||||
|
if associationForeignKey == "" {
|
||||||
|
associationForeignKey = typ.Name() + "Id"
|
||||||
|
}
|
||||||
|
|
||||||
|
// if not many to many, foreign key could be null
|
||||||
|
if many2many == "" {
|
||||||
|
if !reflect.New(typ).Elem().FieldByName(foreignKey).IsValid() {
|
||||||
|
foreignKey = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
field.AfterAssociation = true
|
field.AfterAssociation = true
|
||||||
|
field.JoinTable = &joinTable{
|
||||||
|
joinTable: many2many,
|
||||||
|
foreignKey: foreignKey,
|
||||||
|
associationForeignKey: associationForeignKey,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
if !field.IsTime() && !field.IsScanner() {
|
if !field.IsTime() && !field.IsScanner() {
|
||||||
if scope.HasColumn(field.Name + "Id") {
|
if foreignKey == "" && scope.HasColumn(field.Name+"Id") {
|
||||||
field.ForeignKey = field.Name + "Id"
|
field.JoinTable = &joinTable{foreignKey: field.Name + "Id"}
|
||||||
|
field.BeforeAssociation = true
|
||||||
|
} else if scope.HasColumn(foreignKey) {
|
||||||
|
field.JoinTable = &joinTable{foreignKey: foreignKey}
|
||||||
field.BeforeAssociation = true
|
field.BeforeAssociation = true
|
||||||
} else {
|
} else {
|
||||||
foreignKey := scopeTyp.Name() + "Id"
|
if foreignKey == "" {
|
||||||
|
foreignKey = scopeTyp.Name() + "Id"
|
||||||
|
}
|
||||||
if reflect.New(typ).Elem().FieldByName(foreignKey).IsValid() {
|
if reflect.New(typ).Elem().FieldByName(foreignKey).IsValid() {
|
||||||
field.ForeignKey = foreignKey
|
field.JoinTable = &joinTable{foreignKey: foreignKey}
|
||||||
}
|
}
|
||||||
field.AfterAssociation = true
|
field.AfterAssociation = true
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user