如何在Gorm中删除关联关系的相关模型?

huangapple go评论85阅读模式
英文:

How to delete related models of a relation in Gorm?

问题

所以基本上我有3个模型:User(用户)、Profile(个人资料)和Post(帖子)。

它们的关系如下:User 拥有一个 ProfileProfile 拥有多个 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没有被删除。

删除所有想要的关联的一种方法是使用删除钩子。根据你的设置和关系的强度,可以使用BeforeDeleteAfterDelete。例如:

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 Posts 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())
}

huangapple
  • 本文由 发表于 2022年8月30日 04:22:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/73534284.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定