RelatedSel 是懒加载批量查而非自动 JOIN,需正确定义外键字段(如 orm:"rel(fk);column:category_id")、匹配小写字段名(如 "author" 非 "user")、调用 syncdb 建表,并配合 Filter 实现 INNER JOIN 效果。

RelatedSel 不是“自动 JOIN”,它本质是懒加载的批量查,不配好模型和调用方式,很容易触发 N+1 或字段缺失。
RelatedSel 为什么没查出关联数据?
最常见原因是模型字段没正确定义外键关系。Beego ORM 不靠数据库外键约束,而是靠 struct tag 显式声明:
-
Arctype *Arctype `orm:"rel(fk)"`表示Arctype是外键引用,对应数据库字段默认叫arctype_id(小写 struct 名 +_id) - 如果数据库字段名不是
arctype_id,必须显式指定:`orm:"rel(fk);column:category_id"` - 多对多必须用
`orm:"rel(m2m)"`,否则RelatedSel()完全忽略该字段 - 没调用
orm.RunCommand()+./main orm syncdb的话,自动建表不会生成外键字段,手动建表又漏了xxx_id字段,RelatedSel就查不到任何东西
RelatedSel("user") 中的 "user" 到底指什么?
它匹配的是 struct 中字段名的小写形式,不是数据库表名,也不是模型名。比如:
type Article struct {
Id int
Title string
Author *User `orm:"rel(fk)"`
}
这时必须写 RelatedSel("author"),写 "user" 或 "Author" 都无效。多个关联字段时才需要明确传参,例如:
Author *User `orm:"rel(fk);column:author_id"`Editor *User `orm:"rel(fk);column:editor_id"`- 想只加载作者不加载编辑者 →
RelatedSel("author") - 想两个都加载 →
RelatedSel("author", "editor")或RelatedSel("all")(但慎用"all",会递归加载深层嵌套)
RelatedSel 默认是 LEFT JOIN 还是 INNER JOIN?
它根本不是 JOIN,是两条独立 SQL:先查主表,再用 IN 批量查关联表(类似 SELECT * FROM user WHERE id IN (1,3,5))。所以它天然等效于 LEFT JOIN 的语义(主表数据必返回,关联字段可能为 nil),但性能比真正 JOIN 差。
- 要真正 LEFT JOIN,必须用
QueryTable(&Article{}).RelatedSel("Author").All(&articles),且确保Author字段已按rel(fk)正确声明 - 如果需要 INNER JOIN 效果(即过滤掉无作者的文章),得配合
Filter("Author__isnull", false) - 想查关联表的特定字段(比如只取
User.Name),RelatedSel不支持,只能切回Raw()或用Values()+ 手动 map
RelatedSel 和 LoadRelated 的关键区别
LoadRelated 是实例方法,必须先有主对象;RelatedSel 是 QuerySeter 方法,属于查询链式调用。两者行为差异极大:
-
o.LoadRelated(&article, "Author"):只查单个article的作者,发 1 条额外 SQL -
o.QueryTable(&Article{}).RelatedSel("Author").All(&articles):查一批文章并批量加载作者,发 2 条 SQL(1 条主表 + 1 条 IN 查询) -
LoadRelated(&article, "all")会尝试加载所有rel字段,包括rel(m2m)和深层嵌套,极易导致笛卡尔积或超时 -
RelatedSel("all")同样危险,尤其当模型里有rel(m2m)时,会把中间表也拉一遍,数据量稍大就卡死
真正控制加载深度和范围,得靠 RelateConfig 配合 RelatedSel,而不是依赖 "all" 参数——这点文档很少提,但线上出问题基本都栽在这儿。


















