Your Question
I have something like this:
type MovieAmateur struct {
ID int `gorm:"primary_key";autoIncrement:true;`
Tag []Tag `gorm:"polymorphic:Movie;polymorphicValue:amatuer"`
}
type MovieProfessional struct {
ID int `gorm:"primary_key";autoIncrement:true;`
Tag []Tag `gorm:"polymorphic:Movie;polymorphicValue:professional"`
}
type Tag struct {
ID int `gorm:"primary_key";autoIncrement:true;`
MovieID int
MovieType string
}
This however adds two columns, movie_id and movie_type in the Tag table. So in practice it treats the entity Tag like the association table itself.
Expected answer
The table Tag in my case has a lot of extra fields, I need the association to be represented in an external table with foreign keys from Movie and Tag, e.g.
// Intermediate "bridge" table that couples together Movie* and Tag
type MovieTag struct {
Tag Tag `gorm:"primary_key";autoIncrement:false;`
MovieID int `gorm:"primary_key"`
MovieType int `gorm:"primary_key"`
}
Is it possible with Gorm?
Comment From: resokou
I ended up linking the associations to a new table MovieTag and then manually construct the query:
package main
import (
"log"
"os"
"time"
"fmt"
"github.com/glebarez/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
type MovieAmateur struct {
ID int `gorm:"primary_key";autoIncrement:true;`
Name string
Tags []MovieTag `gorm:"polymorphic:Movie;polymorphicValue:1000"`
}
type MovieProfessional struct {
ID int `gorm:"primary_key";autoIncrement:true;`
Name string
Tags []MovieTag `gorm:"polymorphic:Movie;polymorphicValue:2000"`
}
type Tag struct {
ID int `gorm:"primary_key";autoIncrement:true;`
Name string
}
type MovieTag struct {
TagID int `gorm:"primary_key";autoIncrement:false;`
Tag Tag
MovieID int `gorm:"primary_key"`
MovieType int `gorm:"primary_key"`
}
func main() {
dbLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags),
logger.Config{ // debug queries
SlowThreshold: time.Second,
LogLevel: logger.Info,
IgnoreRecordNotFoundError: true,
Colorful: false,
},
)
db, _ := gorm.Open(sqlite.Open("file::memory:?_fk=on"), &gorm.Config{Logger: dbLogger,})
db.AutoMigrate(&Tag{}, &MovieAmateur{}, &MovieProfessional{}, &MovieTag{},)
tag1 := Tag{Name: "Comic"}
tag2 := Tag{Name: "Sci-Fi"}
db.Create(&tag1)
db.Create(&tag2)
db.Create(&MovieAmateur{Name: "MovieA", Tags: []MovieTag{{Tag: tag1}, {Tag: tag2}},})
db.Create(&MovieProfessional{Name: "MovieP1", Tags: []MovieTag{{Tag: tag1}, {Tag: tag2}},})
db.Create(&MovieProfessional{Name: "MovieP2", Tags: []MovieTag{{Tag: tag2}},})
tags := []Tag{}
db.Table("tags").Select("*").Joins(
"JOIN movie_tags ON tag_id==tags.id AND movie_id=1 AND movie_type=2000").Find(&tags)
for i, tag := range tags {
fmt.Printf("TAG %2d: %+v\n", i, tag)
}
}
The correct combination of Movie type + Movie ID could be passed to an intermediate function (scopes?) via an Enum or by figuring it out using the reflection package I guess. But I don't know if there is an easier way to do it with GORM.
Comment From: github-actions[bot]
This issue has been automatically marked as stale because it has been open 360 days with no activity. Remove stale label or comment or this will be closed in 180 days
Comment From: saeidee
Why you are not having the Name field inside MovieTag? here is a similar example which is having extra fields in the polymorphic table. https://gorm.io/docs/has_many.html#Polymorphism-Association