Fix associations using composite primary keys without ID field, close #3365

This commit is contained in:
Jinzhu 2020-09-03 10:58:48 +08:00
parent 130f24090d
commit fcb666cfa3
2 changed files with 51 additions and 3 deletions

View File

@ -5,6 +5,7 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/clause" "gorm.io/gorm/clause"
"gorm.io/gorm/schema"
) )
func SaveBeforeAssociations(db *gorm.DB) { func SaveBeforeAssociations(db *gorm.DB) {
@ -145,7 +146,7 @@ func SaveAfterAssociations(db *gorm.DB) {
} }
db.AddError(db.Session(&gorm.Session{}).Clauses(clause.OnConflict{ db.AddError(db.Session(&gorm.Session{}).Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: rel.FieldSchema.PrioritizedPrimaryField.DBName}}, Columns: onConflictColumns(rel.FieldSchema),
DoUpdates: clause.AssignmentColumns(assignmentColumns), DoUpdates: clause.AssignmentColumns(assignmentColumns),
}).Create(elems.Interface()).Error) }).Create(elems.Interface()).Error)
} }
@ -168,7 +169,7 @@ func SaveAfterAssociations(db *gorm.DB) {
} }
db.AddError(db.Session(&gorm.Session{}).Clauses(clause.OnConflict{ db.AddError(db.Session(&gorm.Session{}).Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: rel.FieldSchema.PrioritizedPrimaryField.DBName}}, Columns: onConflictColumns(rel.FieldSchema),
DoUpdates: clause.AssignmentColumns(assignmentColumns), DoUpdates: clause.AssignmentColumns(assignmentColumns),
}).Create(f.Interface()).Error) }).Create(f.Interface()).Error)
} }
@ -230,7 +231,7 @@ func SaveAfterAssociations(db *gorm.DB) {
} }
db.AddError(db.Session(&gorm.Session{}).Clauses(clause.OnConflict{ db.AddError(db.Session(&gorm.Session{}).Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: rel.FieldSchema.PrioritizedPrimaryField.DBName}}, Columns: onConflictColumns(rel.FieldSchema),
DoUpdates: clause.AssignmentColumns(assignmentColumns), DoUpdates: clause.AssignmentColumns(assignmentColumns),
}).Create(elems.Interface()).Error) }).Create(elems.Interface()).Error)
} }
@ -310,3 +311,14 @@ func SaveAfterAssociations(db *gorm.DB) {
} }
} }
} }
func onConflictColumns(s *schema.Schema) (columns []clause.Column) {
if s.PrioritizedPrimaryField != nil {
return []clause.Column{{Name: s.PrioritizedPrimaryField.DBName}}
}
for _, dbName := range s.PrimaryFieldDBNames {
columns = append(columns, clause.Column{Name: dbName})
}
return
}

View File

@ -6,6 +6,7 @@ import (
"testing" "testing"
"gorm.io/gorm" "gorm.io/gorm"
. "gorm.io/gorm/utils/tests"
) )
type Blog struct { type Blog struct {
@ -410,3 +411,38 @@ func TestManyToManyWithCustomizedForeignKeys2(t *testing.T) {
t.Fatalf("EN Blog's tags should be cleared") t.Fatalf("EN Blog's tags should be cleared")
} }
} }
func TestCompositePrimaryKeysAssociations(t *testing.T) {
type Label struct {
BookID *uint `gorm:"primarykey"`
Name string `gorm:"primarykey"`
Value string
}
type Book struct {
ID int
Name string
Labels []Label
}
DB.Migrator().DropTable(&Label{}, &Book{})
if err := DB.AutoMigrate(&Label{}, &Book{}); err != nil {
t.Fatalf("failed to migrate")
}
book := Book{
Name: "my book",
Labels: []Label{
{Name: "region", Value: "emea"},
},
}
DB.Create(&book)
var result Book
if err := DB.Preload("Labels").First(&result, book.ID).Error; err != nil {
t.Fatalf("failed to preload, got error %v", err)
}
AssertEqual(t, book, result)
}