大多数表用单字段主键,但某些场景需要多个字段组合作为主键。GORM 支持复合主键定义。
多个字段标记 primaryKey:
type UserLanguage struct {
UserID uint `gorm:"primaryKey"`
LanguageID uint `gorm:"primaryKey"`
Proficiency string
}
生成的 SQL:
CREATE TABLE user_languages (
user_id INT,
language_id INT,
proficiency VARCHAR(50),
PRIMARY KEY (user_id, language_id)
)
var ul UserLanguage
db.First(&ul, UserLanguage{UserID: 1, LanguageID: 2})
或者:
db.Where("user_id = ? AND language_id = ?", 1, 2).First(&ul)
ul := UserLanguage{UserID: 1, LanguageID: 2}
db.Model(&ul).Update("proficiency", "fluent")
ul := UserLanguage{UserID: 1, LanguageID: 2}
db.Delete(&ul)
关联表使用复合主键:
type Order struct {
OrderNo string `gorm:"primaryKey"`
BranchID uint `gorm:"primaryKey"`
Items []OrderItem
}
type OrderItem struct {
OrderNo string `gorm:"primaryKey;index:fk_order"`
BranchID uint `gorm:"primaryKey;index:fk_order"`
ItemID uint `gorm:"primaryKey"`
ProductID uint
Quantity int
}
定义复合外键:
type OrderItem struct {
OrderNo string `gorm:"primaryKey"`
BranchID uint `gorm:"primaryKey"`
ItemID uint `gorm:"primaryKey"`
Order Order `gorm:"foreignKey:OrderNo,BranchID;references:OrderNo,BranchID"`
}
用户语言关联
type UserLanguage struct {
UserID uint `gorm:"primaryKey;index:fk_user"`
LanguageID uint `gorm:"primaryKey;index:fk_language"`
Proficiency string `gorm:"type:enum('beginner','intermediate','advanced','native')"`
CreatedAt time.Time
}
func (UserLanguage) TableName() string {
return "user_languages"
}
订单明细
type OrderItem struct {
OrderID uint `gorm:"primaryKey"`
ItemSeq uint `gorm:"primaryKey"`
ProductID uint
Quantity int
Price float64
}
func (OrderItem) TableName() string {
return "order_items"
}
多租户数据
type TenantData struct {
TenantID uint `gorm:"primaryKey"`
ID uint `gorm:"primaryKey;autoIncrement"`
Data string
}
func (TenantData) TableName() string {
return "tenant_data"
}
自增主键
复合主键中可以有自增字段:
type OrderItem struct {
OrderID uint `gorm:"primaryKey"`
Seq uint `gorm:"primaryKey;autoIncrement"`
}
但只有部分数据库支持复合主键中的自增。
软删除
复合主键表使用软删除:
type UserLanguage struct {
UserID uint `gorm:"primaryKey"`
LanguageID uint `gorm:"primaryKey"`
DeletedAt gorm.DeletedAt `gorm:"primaryKey"`
Proficiency string
}
DeletedAt 需要加入主键,否则软删除后无法再次创建相同记录。
关联查询
复合主键的关联查询需要额外处理:
type Order struct {
OrderNo string `gorm:"primaryKey"`
BranchID uint `gorm:"primaryKey"`
Items []OrderItem
}
var order Order
db.Where("order_no = ? AND branch_id = ?", "ORD001", 1).Preload("Items").First(&order)
复合主键在某些场景下可以用唯一索引替代:
type UserLanguage struct {
ID uint `gorm:"primaryKey;autoIncrement"`
UserID uint `gorm:"uniqueIndex:idx_user_lang"`
LanguageID uint `gorm:"uniqueIndex:idx_user_lang"`
Proficiency string
}
用自增 ID 作为主键,复合唯一索引保证数据唯一性。
好处:
复合主键适合多对多关联表、订单明细等场景。但会增加复杂度,权衡使用。