必须在模型中显式声明rel(m2m)关系,否则loadrelated静默失败;需用registermodel注册并runsyncdb建表生成中间表;插入时先存主记录再addmany绑定;查询推荐relatedsel+all避免n+1问题。

要在Beego ORM中正确实现文章与标签之间的多对多关联查询,必须先在模型结构体中显式声明rel(m2m)关系,否则后续LoadRelated调用将静默失败。
定义多对多关系模型
在models包中定义Article和Tag结构体,关键字段必须使用orm:"rel(m2m)"标签:
方法一:标准声明方式
在Article结构体中添加Tags字段:Tags []*Tag `orm:"rel(m2m)"`
在Tag结构体中添加Articles字段:Articles []*Article `orm:"rel(m2m)"`
方法二:指定中间表名(可选)
若需自定义中间表名,加rel_table参数:Tags []*Tag `orm:"rel(m2m);rel_table(article_tag)"`
【中间表名必须全小写,且不能含大写字母或下划线以外的符号】
方法三:不声明反向关系也能工作
只需在一方声明即可,例如只在Article中写Tags []*Tag `orm:"rel(m2m)"`,Tag结构体里不写Articles字段,ORM仍能生成中间表并支持正向操作。
自动建表与中间表生成
确保init函数中已注册全部模型并启用同步:
第一步:调用RegisterModel注册两个模型orm.RegisterModel(new(Article), new(Tag))
第二步:执行RunSyncdb触发建表orm.RunSyncdb("default", false, true)
这一步会创建article、tag两张主表,【同时自动生成名为article_tag的中间表,字段为article_id和tag_id,均为INT类型且非空】
第三步:检查中间表是否生成
连接数据库执行SHOW TABLES LIKE 'article_tag';,若无结果说明模型未被加载或syncdb未执行。
插入带多对多关系的数据
必须分两步:先存主记录,再建立关联。
先插入Article和Tag实例:a := &Article{Title: "Go并发编程"}; o.Insert(a)<br>t1 := &Tag{Name: "Go"}; o.Insert(t1)<br>t2 := &Tag{Name: "并发"}; o.Insert(t2)
再用AddMany建立多对多绑定:o.QueryTable(&Article{}).Filter("id", a.Id).RelatedSel().AddMany("Tags", []*Tag{t1, t2})
注意:AddMany第一个参数是关系字段名(字符串),不是结构体字段名;第二个参数是目标Tag指针切片。
这一步实际执行INSERT INTO article_tag (article_id, tag_id) VALUES (?, ?),【如果传入nil或空切片,不会报错但也不写入任何记录】
查询时加载关联标签
有两种路径,效果不同:
方法1:QueryTable + RelatedSel + All(推荐)var articles []Article<br>qs := o.QueryTable(&Article{}).RelatedSel("Tags")<br>qs.All(&articles)
该方式一次性发出JOIN查询,返回每条Article连同其Tags切片,性能好且数据完整。
方法2:先查主表再LoadRelated(慎用)var articles []Article<br>o.QueryTable(&Article{}).All(&articles)<br>for i := range articles {<br> o.LoadRelated(&articles[i], "Tags")<br>}
这会产生N+1查询:1次查Article,N次查每个Article对应的Tags,大数据量时明显变慢。
删除多对多关联
只删关联,不删主数据:
从Article侧解除绑定:o.QueryTable(&Article{}).Filter("id", 123).RelatedSel().RemoveRelated("Tags", &Tag{Id: 456})
清空某篇文章所有标签:o.QueryTable(&Article{}).Filter("id", 123).RelatedSel().ClearRelated("Tags")
该操作仅删除article_tag表中对应记录,Article和Tag本身不受影响。











