Reputation: 1920
I can't work out the best way to add an association to a model. I have the following structs
type Beer struct {
ID uint `json:"id"`
Name string `json:"name" gorm:"not null;" sql:"unique"`
Description string `json:"description" gorm:"not null;"`
ImageURL string `json:"image_url"`
AlcoholContent float64 `json:"alcohol_content, default:0"`
Featured bool `json:"featured"`
BrewStart time.Time `json:"brew_start"`
BrewEnd time.Time `json:"brew_end"`
Brewers []Brewer `gorm:"many2many:beer_brewers" json:"brewers"`
}
type Brewer struct {
ID uint `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Title string `json:"title"`
Featured bool `json:"featured"`
Beers []Beer `gorm:"many2many:beer_brewers" json:"beers"`
}
Below is an example of data i have seeded the DB with
Beer{
Name: "some pale ale",
Description: "a description of some pale ale",
ImageURL: "http://via.placeholder.com/350x150",
AlcoholContent: 4.5,
Featured: false,
BrewStart: utils.ParseTime("30-10-2017 13:00 (AEDT)"),
BrewEnd: utils.ParseTime("14-11-2017 13:00 (AEDT)"),
Brewers: []Brewer{
Brewer{FirstName: "john", LastName: "smith", Title: "bottle shaker", Featured: false},
Brewer{FirstName: "joe", LastName: "bloggs", Title: "bottle maker", Featured: true},
},
},
Beer{
Name: "some lager",
Description: "a description of some pale ale",
ImageURL: "http://via.placeholder.com/350x150",
AlcoholContent: 4.5,
Featured: false,
BrewStart: utils.ParseTime("30-10-2017 13:00 (AEDT)"),
BrewEnd: utils.ParseTime("14-11-2017 13:00 (AEDT)"),
Brewers: []Brewer{
Brewer{FirstName: "john", LastName: "smith", Title: "bottle shaker", Featured: false},
Brewer{FirstName: "joe", LastName: "bloggs", Title: "bottle maker", Featured: true},
},
},
However the above creates duplicate Brewers in the Brewer table. My question is, what is the best way to reference a Brewer that already exists but not create another Brewer item in the Brewer table?..and also what is the best way to Append a new Brewer into a Beer collection?
Thanks, Justin
Upvotes: 4
Views: 5983
Reputation: 144
The idea here is the following 1. You create the brewers independently 2. When you append them, add the primary key field "BrewerId" as shown 3. This will lookup the Brewer in the brewers table and add it to the Beer.
import (
"time"
"github.com/jinzhu/gorm"
// used by gorm
_ "github.com/jinzhu/gorm/dialects/postgres"
)
type Beer struct {
BeerId uint `json:"id"`
Name string `json:"name" gorm:"not null;" sql:"unique"`
Description string `json:"description" gorm:"not null;"`
ImageURL string `json:"image_url"`
AlcoholContent float64 `json:"alcohol_content, default:0"`
Featured bool `json:"featured"`
BrewStart time.Time `json:"brew_start"`
BrewEnd time.Time `json:"brew_end"`
Brewers []Brewer `json:"brewers" gorm:"many2many:beer_brewers;association_foreignkey:brewer_id;foreignkey:beer_id"`
}
type Brewer struct {
BrewerId uint `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Title string `json:"title"`
Featured bool `json:"featured"`
}
func migrate() {
// Connection is the connection string
connection := "host=%v port=%v user=%v dbname=%v password=%v sslmode=%v connect_timeout=%v"
db, _ := gorm.Open("postgres", connection)
db.AutoMigrate(&Beer{}, &Brewer{})
db.Model(&Beer{}).Related(&Brewer{}, "Brewers")
db.Create(&Brewer{FirstName: "justin"})
db.Create(&Beer{
Name: "some lager",
Description: "a description of some pale ale",
ImageURL: "http://via.placeholder.com/350x150",
AlcoholContent: 4.5,
Featured: false,
BrewStart: utils.ParseTime("30-10-2017 13:00 (AEDT)"),
BrewEnd: utils.ParseTime("14-11-2017 13:00 (AEDT)"),
}).Association("Brewers").Append(&Brewer{BrewerId: 123,})
}
Upvotes: 2
Reputation: 1920
So i have figured out a solution to what i wanted to do above. To add a new Brewer
into a Beer.Brewers
collection I needed to do the below,
brewerr := Brewer{}
db.Where(&Brewer{FirstName: "justin"}).Find(&brewerr)
beerr := Beer{}
db.Preload("Brewers").Where(&Beer{Name: "some lager"}).Find(&beerr).Association("Brewers").Append(&brewerr)
It's important to note that I needed to Preload
the Beer.Brewers
collection first and THEN append. Failing to Preload resulted in the Append overwriting all of the Brewers
for that Beer
Upvotes: 1
Reputation: 1782
Not sure if you have considered this as an option - better way may be to hold a reference to (a slice of) Brewer IDs in your Beers.Brewers field. As the data is encoded, you can convert these ID's into full field values (using a customized marshal function). This may be suitable, unless you have speed/performance considerations.
Upvotes: 0
Reputation: 116
Try create first beer, then the brewers and usage the .append method to append the brewers in beer.
http://jinzhu.me/gorm/associations.html#association-mode
// Start Association Mode
var user User
db.Model(&user).Association("Languages")
// `user` is the source, it need to be a valid record (contains primary key)
// `Languages` is source's field name for a relationship.
// If those conditions not matched, will return an error, check it with:
// db.Model(&user).Association("Languages").Error
// Query - Find out all related associations
db.Model(&user).Association("Languages").Find(&languages)
// Append - Append new associations for many2many, has_many, will replace current association for has_one, belongs_to
db.Model(&user).Association("Languages").Append([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Append(Language{Name: "DE"})
Upvotes: 2