Many-to-Many & Pivot
Join table models, pivot fields, attach/sync/update-through, and reading pivot data.
Many-to-many relations use a join table. The join table can be just a table name, or it can be modeled when it has business fields.
Relation definition
func (article Article) Tags() oro.Relation {
return oro.ManyToMany(article, "Tags", "Tag").
JoinTable("article_tags").
ForeignKey("ArticleID").
RelatedKey("TagID")
}
Pivot model
type ArticleTag struct {
oro.Model
ArticleID uint64
TagID uint64
Position int
}
func (ArticleTag) Define(s *oro.SchemaBuilder) {
s.Table("article_tags")
s.Field("ArticleID").UnsignedBigInt().Index()
s.Field("TagID").UnsignedBigInt().Index()
s.Field("Position").Int().Default(0)
s.Unique("uk_article_tag", "ArticleID", "TagID")
}
Using a model keeps pivot fields visible and avoids special cases for schema sync.
Attach and sync
err := db.Relation(article.Tags()).Attach(ctx, tag, oro.Map{"position": 10})
err = db.Relation(article.Tags()).Sync(ctx, []*Tag{tagA, tagB})
Read pivot data
When pivot fields matter, query the pivot model directly:
links, err := db.Use[ArticleTag]().Where("ArticleID", article.ID).Get(ctx)
This keeps pivot data explicit instead of hiding it inside related models.