Select all dependencies - go

Imagine the following model:
type (
Account struct {
gorm.Model
CustomID string `gorm:"index;unique"`
Name string
Profiles []*Profiles `gorm:"ForeignKey:AccountID"`
}
Profile struct {
gorm.Model
AccountID uint `gorm:"index"`
TheFoo *Foo
TheDoo *Doo
}
Foo struct {
ProfileID uint `gorm:"index"`
Boo string
}
Doo struct {
ProfileID uint `gorm:"index"`
Moo string
}
)
All my attempts of getting the entire structure always fails. acc is always filled with only the account data and no profiles.
I even expereimented with this db.Model(&acc).Related(&Profile{}) stuff but still no success. The (lets say, pretty bad) docs also do not clarify this.
var acc Account
db.Find(&acc, "custom_id = ?", myCustomID)
how would you actually do this?

I believe you can use the Preload method which supports ne, i.e.:
account := new(Account)
db.Preload("Profiles.TheDoo").Preload("Profiles.TheFoo").Find(account, "custom_id = ?", myCustomID)
I haven't checked yet if you actually need to preload Profiles as well, but it wouldn't hurt to use it if it turns out you do.

Can you add your code for when you call the related function? http://jinzhu.me/gorm/associations.html#has-many What Im seeing on the documentation for has-many it should look like this.
var acc Account
db.Find(&acc, "custom_id = ?", myCustomID)
db.Model(&acc).Related(&profiles)

Related

Mapping one type to another

Let's say I have the following types.
type Contract struct {
Id string `json:"id" gorm:"column:uuid"`
Name string `json:"name" gorm:"column:name"`
Description string `json:"descr" gorm:"column:descr"`
ContractTypeId int `json:"contract_type_id" gorm:"column:contract_type_id"`
}
type ContractModel struct {
Id string `json:"id" gorm:"column:uuid"`
Name string `json:"name" gorm:"column:name"`
Description string `json:"descr" gorm:"column:descr"`
}
I have a SQL query using gorm to scan results into a contract object.
How can I map the values from the contract object into contractModel object?
I tried using the package go-automapper as such:
automapper.Map(contract, ContractModel{})
I want to drop the ContractTypeId.
Can I do this for multiple types in a list?
var contractModels []ContractModel
automapper.Map(contracts, &contractModels)
You can do either:
models := []ContractModel{}
automapper.Map(contracts, &models)
Or call automapper.Map in a loop:
models := make([]ContractModel, len(contracts))
for i := range contracts {
automapper.Map(contracts[i], &models[i])
}
You should be aware that automapper uses reflection behind the scenes and thus is much slower than straight forward non-polymorphic copying like #ThinkGoodly suggests. It's a totally fine solution if performance isn't top priority though.

Control over unexported struct fields

So this is my first question in stackoverflow. :)
We have defined a struct in org package like below:
type Employee struct {
FirstName, LastName string
salary int
}
and then in main.go file, we are initializing the struct like below:
func main() {
ross := Employee {
FirstName: "Ross",
LastName: "Geller",
}
fmt.Println(ross)
}
The output will be like below:
{Ross Geller 0}
As salary field is not exported from the Employee struct type, so it's displaying the zero value of int. An end-user will assume that the salary of this employee is 0.
So is there any way to control the unexported fields?
What is the best approach to deal with such a problem in a real-time scenario?
Is this really a problem?
If you're really worried about it, you can override the .String of Employee:
https://play.golang.org/p/PncEOGVP2HP
func (e Employee) String() string {
return fmt.Sprintf("%v", struct{
FirstName string
LastName string
}{e.FirstName, e.LastName})
}
But in reality, are they going to be seeing the output from the console of your program? Most likely this is a non-issue.
Well, If you want to initialize the field you can always write an exported function or method to do that such as
func New(first,last,salary string) Employee{
//...
}
The reason why you can have unexported types is to be able to create something called an opaque type.
You can have methods on your data setters and getters and do complex things without worrying about user braking the internal state of your data.
Imagine you are writing a drawing app and you have a painter Struct which keeps track of cursor and current color and stuff. You really would not want your user to be able to mess with your painter manually. that would break everything.
So the user creates the painter through an initializer and passes it around as a Painter type and using methods such as moveTo,lineTo which updates the state internally.

Query with 'has one' association (one-to-one)

I'm playing a bit with Gorm while I'm trying to decide which ORM library fit the most for my needs.
Important to mention that I'm currently working with Sqlite.
Following the guide I created two structs:
type Color struct {
gorm.Model
UserID uint
Name string
}
//User struct define a basic user model
type User struct {
gorm.Model
Username string
Email string
FirstName string
LastName string
Password string
CreationDate time.Time
DOB time.Time
IgnoreMe int `gorm:"-"` // Ignore this field
Color Color `gorm:"foreignkey:ColorRefer"`
ColorRefer uint
}
when I'm creating a DB with
func CreateTables() {
user := dm.User{}
color := dm.Color{}
GormDB.CreateTable(&color)
GormDB.CreateTable(&user)
GormDB.Model(&user).AddForeignKey("ColorRefer", "colors(id)", "CASCADE", "CASCADE")
}
or with:
func CreateTables() {
GormDB.AutoMigrate(&dm.User{},&dm.Color{})
}
Sadly it's not working as I would of expect and create the foreign key automatically, but it's works when I do it manually.
My main problem is when I'm trying to query Users
//QueryByStructExample query users table by the struct non-zero (non-default) fields.
func QueryByStructExample(userStruct dm.User) []dm.User {
var results []dm.User
GormDB.Where(userStruct).Find(&results)
return results
}
I created the following function in a try to query users by email with the color property which is my color struct and I tried to play with a lot with the Model,Related and the Association functions, and nothing seems to work and (I'm avoiding to use join by purpose).
The end result is that it query my User but without the color (only with the ID in my colorRefer)
any suggestion?
Do you mean to preload the Color struct? If yes did you try to query it like that
GormDB.Preload('Color').Where(userStruct).Find(&results)

How to update with a many-to-many relationship

I'm facing a difficulty with the go orm gorm:
I have a structure like this:
type Data struct {
gorm.Model
UserID int `json:"user_id,omitempty"`
AnswerID int `json:"answer_id,omitempty"`
Entities []Entity `gorm:"many2many:data_entities;"`
}
type Entity struct {
gorm.Model
Name string
}
And now, either if I do:
db.Model(&data).Where(Data{AnswerID: data.AnswerID}).Assign(&data).FirstOrCreate(&data)
Or
db.Model(&data).Where(Data{AnswerID: d.AnswerID}).Update(&data)
My many-to-many fields aren't updated but created... Leading to duplications if already exists.
If I try to play with the Related() function, it simply stop updating the foreign field.
Is there a way to update or create properly every tables linked?
I do it like this:
To update your data just pass a struct with only the fields you wanna update:
db.Model(&data).Updates(Data{UserID: 2, AnswerID: 2})
and to add new entities:
db.Model(&data).Association("Entities").Append([]*Entity{&Entity{Name: "mynewentity"}})
The way I handled it is using a custom join table and just inserting or deleting the rows manually.
type DataEntity struct {
DataID string `gorm:"primaryKey"`
EntityID string `gorm:"primaryKey"`
CreatedAt time.Time
DeletedAt gorm.DeletedAt
}
set up the join table
err := db.AutoMigrate(&Data{}, &Entity{}, &DataEntity{})
err = db.SetupJoinTable(&Data{}, "Entities", &DataEntity{})
Then for deleting entities:
db.Unscoped().Model(&Data).Association("Entities").Clear()
To add entities:
dataEntities := []DataEntity{DataEntity{DataID:dataid,EntityID:eid}}
dbConnection.Create(&dataEntites)
Slightly cumbersome but it's the only solution I've found so far.
So far the only I found is this one:
db.Table("entities").
Where(
"id in (?)",
db.Table("data_entities").
Select("entity_id").
Where(
"data_id = ?",
data.ID,
).
QueryExpr(),
).
Where("entity_name = ?", *entityName).
Update(&data.Entity)
But I found 2 problems here:
1) Impossible to do a deeper subrequest:
Select("entity_id").
Where(
"data_id = ?",
data.ID,
)...
Won't work if instead of data.ID I want to go deeper with an other sub-request.
2) in case of multiple many-2-many I assume I would need to duplicate the query.
I was able to resolve according to the documentation using the Association.Replace
http://gorm.io/docs/associations.html#Replace-Associations
db.Debug().First(&data)
data.Name = "New Name"
db.Save(&data).Association("Entities").Replace([]Entity{{Name: "mynewentity"}})

golang gorm update associations on save

is there a way to automatically remove associations when an object is saved?
something like this:
type Parent struct {
gorm.Model
Name string
Children []*Child
}
type Child struct {
gorm.Model
Name string
ParentID uint
}
func myFunc(db *gorm.DB) {
p := &Parent{Name: "foo", Children:[]*Child{ {Name:"Bar"}, {Name:"Foobar"}}}
db.Save(&p)
p.Children = p.Children[1:]
db.Save(&p) // both children still exist in the database. i'd like the first child to be deleted here
}
`
I've found some tricks with db.Model(&Parent).Association("Children").Clear(), but that just sets the ParentID value to NULL, rather than deleting the record. Is there a simple way of doing this?
Many thanks in advance :)
I think you just simply use the physical batch delete like following code:
db.Unscoped().Where("parent_id = ?", p.ID).Delete(Child{})
Hope this help.

Resources