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.
Related
I'm trying to cascade delete the below structure:
type Action struct {
gorm.Model
Name string
Email string
Halls []Hall `gorm:"foreignKey:ActionID"`
}
type Hall struct {
gorm.Model
Name string
ActionID uint
Stream Stream `gorm:"foreignKey:HallID"`
}
type Stream struct {
ID uint `gorm:"primaryKey"`
HallID uint
Name string
}
db.Select("Halls").Delete(&action) - works fine for selected action and with all related halls.
How can I delete this one and related streams?
Something like:
db.Select("Halls", "Streams").Delete(&action)
db.Select("Streams").Select("Halls").Delete(action)
doesn't work.
Thanks
you can not use delete and select at same time in same query means it not feasible solution to do that
but yeah you can use this reference link
Try Deleting action with where condition and specify HallID
db.Where("hall_id IN ?",HallID).Delete(&action)
and SET HallID to constraint:OnDelete:CASCADE in Stream so when you delete Halls then automatically Streams will be deleted whichever associated with that Halls
I cannot comment on M_x so I'll put this as an answer.
You are allowed to 'Delete' with 'Select' with associations. See https://gorm.io/docs/associations.html#Delete-with-Select
However, I'm also looking for a solution for nested associations where the nested is a slice of a struct.
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"}})
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)
I'm trying to create a self-reference in a (my)sql table using golang gorm. At the moment my code looks like this:
type Person struct {
gorm.Model
Name string
Children []*Person `gorm:"ForeignKey:ParentID"`
ParentID uint
}
func main() {
/* code to get database connection omitted */
p := &Person{Name:"Sally"}
db.Create(p)
children := []*Person{ {Name:"Jane", ParentID:p.ID},
{Name:"Tom", ParentID:p.ID}}
for _, child := range children {
db.Create(child)
}
var children2 []*Person
db.Model(p).Related(children2, "ParentID")
}
The code is failing with an error "reflect.Value.Set using unaddressable value".
Does anybody know how to get this relationship working using go gorm?
Many thanks in advance :)
Fortunately gorm have added lately this feature (reference: here).
In your case should be like this:
type Person struct {
gorm.Model
Name string
Children []*Person `gorm:"many2many: children;association_jointable_foreignkey:children_id"`
}
I have 2 structs with data like this:
type User struct {
Pics Pic[]
}
type Pic struct {
Id int
UserId int64
}
Although everytime I insert an User, Each of the pics are inserted on their table everytime I find the users, pics are not populated:
var users []User
db.Limit(pagesize).Where("updated_at > ?", date).Find(&users)
Am I doing something wrong?
Your models (the structs) don't really make sense because User have a Pic array indicates a 'one to many' user to pics relationship however your user has no id property itself and there for cannot be related to items on the Pic table.
User should have a property Id which will be it's primary key and UserId is a foreign key on Pic that relates to it. Without the 'relation' between these two tables/entities there's no way you're going to return pics by querying users.
I'm not sure what all you need to do to make your code work since the example is incomplete but the first thing you need is an Id property which you should designate as a Primarykey with gorm annotations. You also should have annotations on the Pic struct saying UserId is a foreign key and Id is it's primary key.
Also, just fyi your array is not embedded. Embedding is a language feature which you're not using, if you embed the property it has no name and it's properties can be accessed directly from an instance of the embedding type.
I had these issues once. Then I used Join function.
See my example that works just fine:
type FileType struct {
Id int
}
type File struct {
Id int
FileType `xorm:"extends"`
}
file := File{Id: id}
has, err := eng.
Join("INNER", "FileType", "FileType.IdFileType = File.IdFileType").
Get(&file)
You probably know by now. You got to think as if you are creating a SQL table with 1-to-many relationship. Here is an example:
type Entry struct {
ID int
Name string
...
ContainerID int
}
type Container struct {
ID int
Tag int
Name string
...
Entries []Entry `gorm:"foreignkey:ContainerID"`
}
The trick is to populate it. I am yet to find how to make it in one try. For every such dependency, you got to run something like:
c := getContainerFromDB(...)
if err := getROConn().Model(c).Related(&c.Entries, "Entries").Error; err != nil {
return errors.Wrap(err, "error getting container field")
}
Try Preload
db.Limit(pagesize).Where("updated_at > ?", date).Preload("Pics").Find(&users)