英文:
How to delete related models of a relation in Gorm?
问题
所以基本上我有3个模型:User
(用户)、Profile
(个人资料)和Post
(帖子)。
它们的关系如下:User
拥有一个 Profile
。Profile
拥有多个 Post
。
它们的结构如下:
type User struct {
Base // 包含该对象的uuid、createdAt、updatedAt
Role string `json:"role"`
Username string `json:"username" gorm:"unique"`
Password string `json:"password"`
Profile Profile `gorm:"constraint:OnDelete:CASCADE;"`
}
type Profile struct {
Base // 包含该对象的uuid、createdAt、updatedAt
UserId string `json:"user_id"`
Name string `json:"name"`
Bio string `json:"bio"`
Age uint8 `json:"age"`
Posts []Post `gorm:"constraint:OnDelete:CASCADE;"`
}
type Post struct {
Base // 包含该对象的uuid、createdAt、updatedAt
ProfileId string `json:"profile_id"`
Caption string `json:"caption"`
Likes uint32 `json:"num_likes" gorm:"default:0"`
}
我希望的结果是当我删除用户时,个人资料和与之相关的所有帖子都被删除。我在关系型数据库中的唯一其他经验是Django,那里这是自动完成的。
实际发生的情况是当我删除用户时,个人资料被删除,但帖子仍然存在于数据库中。
这是我删除用户的方式:
...
base := models.Base{Id: id}
if err := configs.Database.Select(clause.Associations).Delete(&models.User{Base: base}).Error; err != nil {
return c.Status(400).JSON(err.Error())
}
...
我已经查看了这个,但它并没有提供太多帮助。我该如何实现这个功能?
谢谢!
英文:
So basically I have 3 models: User
, Profile
, and Post
.
They are related like so: User
has one Profile
. Profile
has many Post
They look like this:
type User struct {
Base // holds this object's uuid, createdAt, updatedAt
Role string `json:"role"`
Username string `json:"username" gorm:"unique"`
Password string `json:"password"`
Profile Profile `gorm:"constraint:OnDelete:CASCADE;"`
}
type Profile struct {
Base // holds this object's uuid, createdAt, updatedAt
UserId string `json:"user_id"`
Name string `json:"name"`
Bio string `json:"bio"`
Age uint8 `json:"age"`
Posts []Post `gorm:"constraint:OnDelete:CASCADE;"`
}
type Post struct {
Base // holds this object's uuid, createdAt, updatedAt
ProfileId string `json:"profile_id"`
Caption string `json:"caption"`
Likes uint32 `json:"num_likes" gorm:"default:0"`
}
What I want to happen is when I delete the user, I want the profile to be deleted and all the posts that are related to it. My only other experience with relational databases are Django where this is automatic.
What actually happens is when I delete the user, the profile gets deleted but the posts remain in the database.
This is how I am deleting the user:
...
base := models.Base{Id: id}
if err := configs.Database.Select(clause.Associations).Delete(&models.User{Base: base}).Error; err != nil {
return c.Status(400).JSON(err.Error())
}
...
I've already looked at this but its not very helpful. How could I accomplish this?
Thank you!
答案1
得分: 1
根据你发布的问题链接和其他相关问题,可能无法在多于一层的嵌套关系中使用clause.Associations
。在你的情况下,与你的User
相关的Profile
被删除了,但与Profile
相关的Post
没有被删除。
删除所有想要的关联的一种方法是使用删除钩子。根据你的设置和关系的强度,可以使用BeforeDelete
或AfterDelete
。例如:
func (u *User) BeforeDelete(tx *gorm.DB) (err error) {
if err := tx.Joins("profiles p ON p.id = posts.profile_id").Joins("users u ON u.id = p.user_id").Where("u.id = ?", u.Base.Id).Delete(&Post{}).Error; err != nil {
return err
}
return tx.Joins("users u ON u.id = profiles.user_id").Where("u.id = ?", u.Base.Id).Delete(&Profile{}).Error
}
这样,当你执行configs.Database.Delete(&models.User{Base: base})
时,它会先执行钩子,然后执行这个查询。
另一种方法是在钩子函数中分别执行所有的查询:
base := models.Base{Id: id}
if err := configs.Database.Joins("profiles p ON p.id = posts.profile_id").Joins("users u ON u.id = p.user_id").Where("u.id = ?", base.Id).Delete(&Post{}).Error; err != nil {
return c.Status(400).JSON(err.Error())
}
if err := configs.Database.Joins("users u ON u.id = profiles.user_id").Where("u.id = ?", base.Id).Delete(&Profile{}).Error; err != nil {
return c.Status(400).JSON(err.Error())
}
if err := configs.Database.Delete(&models.User{Base: base}).Error; err != nil {
return c.Status(400).JSON(err.Error())
}
英文:
Based on the issue link you posted, and other related issues, it might not be possible to use clause.Associations
for relations nested deeper than one level. In your case, the Profile
related to your User
is deleted, but not the Post
s related to the Profile
.
One way to delete all wanted associations is to use a delete hook. Either BeforeDelete
or AfterDelete
, depending on your setup and how strong your relationships are. For example:
func (u *User) BeforeDelete(tx *gorm.DB) (err error) {
if err := tx.Joins("profiles p ON p.id = posts.profile_id").Joins("users u ON u.id = p.user_id").Where("u.id = ?", u.Base.Id).Delete(&Post{}).Error; err != nil {
return err
}
return tx.Joins("users u ON u.id = profiles.user_id").Where("u.id = ?", u.Base.Id).Delete(&Profile{}).Error
}
This way, when you execute configs.Database.Delete(&models.User{Base: base})
, it will execute the hook first, then this query.
Another way would be to execute all the queries from the hook function separately:
base := models.Base{Id: id}
if err := configs.Database.Joins("profiles p ON p.id = posts.profile_id").Joins("users u ON u.id = p.user_id").Where("u.id = ?", base.Id).Delete(&Post{}).Error; err != nil {
return c.Status(400).JSON(err.Error())
}
if err := configs.Database.Joins("users u ON u.id = profiles.user_id").Where("u.id = ?", base.Id).Delete(&Profile{}).Error; err != nil {
return c.Status(400).JSON(err.Error())
}
if err := configs.Database.Delete(&models.User{Base: base}).Error; err != nil {
return c.Status(400).JSON(err.Error())
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论