多态关联让一个模型可以关联多种不同的模型。评论可以属于文章、视频、图片;图片可以属于用户、商品、店铺。这种灵活性在复杂业务中很有用。
传统关联需要预先知道关联的模型类型。评论表有 article_id 字段,只能关联文章。
多态关联用两个字段解决:
commentable_id - 关联对象的 IDcommentable_type - 关联对象的类型这样评论可以关联文章、视频、图片等任何模型。
评论可以属于文章或视频:
type Comment struct {
ID uint
Content string
CommentableID uint
CommentableType string
}
type Article struct {
ID uint
Title string
Comments []Comment `gorm:"polymorphic:Commentable;"`
}
type Video struct {
ID uint
Title string
Comments []Comment `gorm:"polymorphic:Commentable;"`
}
创建评论:
article := Article{Title: "文章标题"}
db.Create(&article)
comment := Comment{
Content: "这是评论",
CommentableID: article.ID,
CommentableType: "articles",
}
db.Create(&comment)
或者通过关联创建:
article := Article{
Title: "文章标题",
Comments: []Comment{
{Content: "评论1"},
{Content: "评论2"},
},
}
db.Create(&article)
CommentableType 自动设为表名 articles。
查询文章的评论:
var article Article
db.Preload("Comments").First(&article, 1)
fmt.Println(article.Comments)
查询视频的评论:
var video Video
db.Preload("Comments").First(&video, 1)
fmt.Println(video.Comments)
图片可以属于用户或商品:
type Image struct {
ID uint
URL string
ImageableID uint
ImageableType string
}
type User struct {
ID uint
Name string
Avatar Image `gorm:"polymorphic:Imageable;"`
}
type Product struct {
ID uint
Name string
Image Image `gorm:"polymorphic:Imageable;"`
}
创建用户头像:
user := User{
Name: "张三",
Avatar: Image{
URL: "avatar.jpg",
},
}
db.Create(&user)
标签可以用于文章、视频、图片:
type Tag struct {
ID uint
Name string
Articles []Article `gorm:"many2many:taggables;polymorphic:Taggable;"`
Videos []Video `gorm:"many2many:taggables;polymorphic:Taggable;"`
}
type Article struct {
ID uint
Title string
Tags []Tag `gorm:"many2many:taggables;polymorphic:Taggable;"`
}
type Video struct {
ID uint
Title string
Tags []Tag `gorm:"many2many:taggables;polymorphic:Taggable;"`
}
中间表 taggables 结构:
CREATE TABLE taggables (
tag_id INT,
taggable_id INT,
taggable_type VARCHAR(255),
PRIMARY KEY (tag_id, taggable_id, taggable_type)
)
默认 CommentableType 存储表名。自定义:
type Comment struct {
ID uint
Content string
CommentableID uint
CommentableType string
}
type Article struct {
ID uint
Title string
Comments []Comment `gorm:"polymorphic:Commentable;polymorphicValue:article"`
}
type Video struct {
ID uint
Title string
Comments []Comment `gorm:"polymorphic:Commentable;polymorphicValue:video"`
}
CommentableType 存储自定义值 article 或 video。
从评论反向查询关联对象:
var comment Comment
db.First(&comment, 1)
switch comment.CommentableType {
case "articles":
var article Article
db.First(&article, comment.CommentableID)
case "videos":
var video Video
db.First(&video, comment.CommentableID)
}
封装成方法:
func (c *Comment) GetCommentable(db *gorm.DB) interface{} {
switch c.CommentableType {
case "articles":
var article Article
db.First(&article, c.CommentableID)
return &article
case "videos":
var video Video
db.First(&video, c.CommentableID)
return &video
}
return nil
}
评论系统
评论可以属于文章、视频、动态:
type Comment struct {
gorm.Model
Content string
CommentableID uint
CommentableType string
UserID uint
User User
}
type Post struct {
gorm.Model
Content string
Comments []Comment `gorm:"polymorphic:Commentable;"`
}
type Article struct {
gorm.Model
Title string
Comments []Comment `gorm:"polymorphic:Commentable;"`
}
收藏系统
用户可以收藏文章、商品、店铺:
type Favorite struct {
gorm.Model
UserID uint
FavoritableID uint
FavoritableType string
}
type User struct {
gorm.Model
Favorites []Favorite
}
type Article struct {
gorm.Model
Title string
Favorites []Favorite `gorm:"polymorphic:Favoritable;"`
}
type Product struct {
gorm.Model
Name string
Favorites []Favorite `gorm:"polymorphic:Favoritable;"`
}
点赞系统
type Like struct {
gorm.Model
UserID uint
LikeableID uint
LikeableType string
}
type Article struct {
gorm.Model
Title string
Likes []Like `gorm:"polymorphic:Likeable;"`
}
type Comment struct {
gorm.Model
Content string
Likes []Like `gorm:"polymorphic:Likeable;"`
}
索引
多态关联需要复合索引:
type Comment struct {
ID uint
CommentableID uint
CommentableType string `gorm:"index:idx_commentable"`
}
或数据库层面:
CREATE INDEX idx_commentable ON comments(commentable_type, commentable_id);
外键约束
多态关联无法使用数据库外键约束,因为 CommentableID 可能指向不同表。需要在应用层保证数据一致性。
查询性能
按类型查询时,确保有索引:
db.Where("commentable_type = ? AND commentable_id = ?", "articles", 1).Find(&comments)
多态关联提供了灵活的关联方式,适合评论、收藏、点赞等通用功能。注意索引优化和应用层约束。