GORM如何获取递归关联的全部层级Children字段值
GORM 递归查询全层级分类解决方案
GORM 默认的Preload方法仅会加载直接关联的第一层子资源,要获取全层级的递归分类,可选用以下两种成熟方案:
方案1:动态递归预加载(适配任意层级)
通过自定义预加载回调函数实现无限层级递归加载,无需提前知道最大层级:
// 递归预加载回调 func preloadChildren(db *gorm.DB) *gorm.DB { return db.Preload("Children", preloadChildren) } // 查询示例:默认查询所有顶级分类并加载全量子分类 var categories []Category err := DB.Scopes(preloadChildren).Where("parent_id IS NULL").Find(&categories).Error if err != nil { // 自行处理查询错误 }
原理:每一层的Children关联都会复用同一个递归预加载函数,直到对应层级没有子分类时自动停止查询。
方案2:固定层级预加载(适配层级已知场景)
如果业务中分类的最大层级是固定的,比如最多3级,可以直接链式写全层级预加载路径,写法更简单:
var categories []Category // 示例适配最大4级分类:顶级→1级→2级→3级 err := DB.Preload("Children.Children.Children.Children").Where("parent_id IS NULL").Find(&categories).Error
注意:如果实际分类层级超过你指定的预加载层数,超出部分的子分类不会被加载。
大数据量优化方案
如果分类数据量级较大,以上两种方案会产生N+1查询问题,建议直接使用数据库递归CTE查询,性能提升明显,PostgreSQL示例如下:
var categories []Category err := DB.Raw(` WITH RECURSIVE category_tree AS ( -- 递归起点:所有顶级分类 SELECT id, name, parent_id FROM categories WHERE parent_id IS NULL UNION ALL -- 递归逻辑:关联查询所有子分类 SELECT c.id, c.name, c.parent_id FROM categories c INNER JOIN category_tree ct ON c.parent_id = ct.id ) SELECT * FROM category_tree ORDER BY parent_id, id `).Scan(&categories).Error // 查询得到扁平化的全量分类后,可自行遍历组装为树形结构
内容的提问来源于stack exchange,提问作者Saifullah Shahen
相关产品推荐
相关产品推荐

