GORM多对多关联下通过分类ID查询产品的最优方案
问题:GORM多对多关联下通过分类ID查询产品的最优实现
我正在使用Go 1.19及ORM框架GORM,需要通过分类ID查询对应的产品。产品表与分类表为多对多关系,关联表为product_categories。当收到带分类ID的GET请求时,需返回该分类下的所有产品。
模型结构
Product模型
// Product模型 // Categories many2many:product_categories type Product struct { ID uint `gorm:"primarykey" json:"id"` Slug string `gorm:"unique;size:255;" json:"slug"` Title string `gorm:"size:255;not null" json:"title"` Code string `gorm:"size:255;not null" json:"code"` BrandID uint `json:"-"` Brand Brand `json:"brand"` ShortDescription string `gorm:"not null" json:"short_description"` Description string `json:"description"` Price uint `gorm:"not null" json:"price"` Quantity uint `json:"qnt"` DiscountPrice uint `json:"discount_price"` Categories []Category `gorm:"many2many:product_categories;" json:"categories"` Attributes []Attribute `json:"attributes"` ProductImages []ProductImage `json:"product_images"` CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` }
Category模型
// Category模型 // Products many2many:product_categories type Category struct { ID uint `gorm:"primarykey" json:"id"` Name string `gorm:"size:255;not null" json:"name"` Icon string `gorm:"size:255;not null" json:"icon"` Image string `gorm:"size:255;not null" json:"image"` Weight int32 `gorm:"AUTO_INCREMENT" json:"weight"` Products []Product `gorm:"many2many:product_categories;" json:"products"` CreatedAt time.Time `json:"-"` UpdatedAt time.Time `json:"-"` }
ProductCategory模型
// ProductCategory模型 // 该表由GORM自动生成 type ProductCategory struct { CategoryID int `gorm:"primaryKey" json:"-"` ProductID uint `gorm:"primaryKey" json:"-"` }
现有实现(非最优)
我目前采用间接方式实现:先查询ProductCategory表获取产品ID,存入切片后再查询产品,代码如下:
func (q *Queries) GetProductsbyCat(id uint) ([]models.Product, error) { // 定义products和product_cat变量 products := []models.Product{} product_cats := []models.ProductCategory{} // 查询product_cat并赋值 err := q.Model(&product_cats).Limit(10).Find(&product_cats, "category_id = ?", id).Error if err != nil { // 返回空对象和错误 return nil, err } // 定义产品ID切片 productIds := []int{} // 遍历product_cats,将产品ID添加到productIds中 for _, v := range product_cats { productIds = append(productIds, int(v.ProductID)) } // 查询产品 err = q.Model(&products).Order("id desc").Preload("ProductImages").Find(&products, productIds).Error if err != nil { // 返回空对象和错误 return nil, err } return products, nil }
请问在该场景下,使用GORM实现多对多关联查询产品的最优方式是什么?
最优实现方案
方案1:通过Category模型关联查询(推荐,符合GORM关联设计)
利用GORM的预加载能力,直接从分类模型获取关联的产品集合,代码更简洁,且减少数据库查询次数:
import "sort" func (q *Queries) GetProductsbyCat(id uint) ([]models.Product, error) { var category models.Category // 查询分类并预加载关联的产品及产品图片 err := q.Model(&models.Category{}). Preload("Products.ProductImages"). Preload("Products.Brand"). // 若需要品牌信息可添加 Where("id = ?", id). First(&category).Error if err != nil { return nil, err } // 按产品ID倒序排序(保留原有逻辑) sort.Slice(category.Products, func(i, j int) bool { return category.Products[i].ID > category.Products[j].ID }) return category.Products, nil }
方案2:直接查询Product模型(适合仅需产品数据的场景)
通过JOIN关联表直接过滤产品,逻辑更直接,便于添加分页、排序等条件:
func (q *Queries) GetProductsbyCat(id uint) ([]models.Product, error) { var products []models.Product err := q.Model(&models.Product{}). Preload("ProductImages"). Preload("Brand"). // 关联中间表过滤分类ID Joins("JOIN product_categories ON product_categories.product_id = products.id"). Where("product_categories.category_id = ?", id). Order("products.id desc"). Limit(10). // 保留原有分页限制 Find(&products).Error if err != nil { return nil, err } return products, nil }
方案优势对比
原有方案需要两次独立数据库查询,存在额外的数据库往返开销;上述两种方案均通过一次主查询(配合预加载的关联查询,GORM会自动优化)完成逻辑,不仅代码更简洁易维护,性能也更优,完全贴合GORM多对多关联的设计意图。
内容的提问来源于stack exchange,提问作者Hardy
相关产品推荐
相关产品推荐

