How to cascade (soft) delete has many relationships in GORM?

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

How to cascade (soft) delete has many relationships in GORM?

问题

我正在使用GORM实现一些删除功能。我的想法是级联删除,即当删除父行时,子行也会被删除。我尝试过使用delete with select。但它只删除了父记录。

func DeleteProject(db *gorm.DB, id uint) (Project, error) {
    var project Project
    if err := db.Select(clause.Associations).Delete(&project, id).Error; err != nil {
        return Project{}, err
    }
    return project, nil
}

我有以下模型:

type Project struct {
    ID           uint           `gorm:"primary_key" json:"id"`
    CreatedAt    time.Time      `json:"created_at"`
    UpdatedAt    time.Time      `json:"updated_at"`
    DeletedAt    gorm.DeletedAt `gorm:"index" json:"deleted_at"`
    TicketNumber string         `gorm:"size:6;unique;not null" json:"ticketnumber"`
    Name         string         `json:"name"`
    MailingList  string         `json:"mailinglist"`
    Environment  string         `gorm:"not null" json:"environment"`
    UserID       uint           `gorm:"index" json:"user_id"`
    Diagrams     []Diagram      `json:"diagrams"`
}

type Diagram struct {
    ID        uint           `gorm:"primary_key" json:"id"`
    CreatedAt time.Time      `json:"created_at"`
    UpdatedAt time.Time      `json:"updated_at"`
    DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"`
    Data      string         `json:"data"`
    ProjectID uint           `gorm:"index" json:"project_id"`
    Instances []Instance     `json:"instances"`
}

type Instance struct {
    ID        uint           `gorm:"primary_key" json:"id"`
    CreatedAt time.Time      `json:"created_at"`
    UpdatedAt time.Time      `json:"updated_at"`
    DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"`
    Key       uint           `json:"key"`
    DiagramID uint           `gorm:"index" json:"diagram_id"`
}

一个项目可以有多个图表,一个图表可以有多个实例。但是当我运行DeleteProject函数时,它只删除了Project,而没有删除关联的图表和实例。

在这种情况下,我该如何删除一个项目及其关联的图表和实例?

英文:

I am implementing some delete functionality using GORM. My idea is to cascade delete where when the parent row is deleted the childern are deleted aswell. I have tried the delete with select. But it only deletes the parent record.

func DeleteProject(db *gorm.DB, id uint) (Project, error) {
	var project Project
	if err := db.Select(clause.Associations).Delete(&project, id).Error; err != nil {
		return Project{}, err
	}
	return project, nil
}

I have the following model:

type Project struct {
	ID           uint           `gorm:"primary_key" json:"id"`
	CreatedAt    time.Time      `json:"created_at"`
	UpdatedAt    time.Time      `json:"updated_at"`
	DeletedAt    gorm.DeletedAt `gorm:"index" json:"deleted_at"`
	TicketNumber string         `gorm:"size:6;unique;not null" json:"ticketnumber"`
	Name         string         `json:"name"`
	MailingList  string         `json:"mailinglist"`
	Environment  string         `gorm:"not null" json:"environment"`
	UserID       uint           `gorm:"index" json:"user_id"`
	Diagrams     []Diagram      `json:"diagrams"`
}

type Diagram struct {
	ID        uint           `gorm:"primary_key" json:"id"`
	CreatedAt time.Time      `json:"created_at"`
	UpdatedAt time.Time      `json:"updated_at"`
	DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"`
	Data      string         `json:"data"`
	ProjectID uint           `gorm:"index" json:"project_id"`
	Instances []Instance     `json:"instances"`
}

type Instance struct {
	ID        uint           `gorm:"primary_key" json:"id"`
	CreatedAt time.Time      `json:"created_at"`
	UpdatedAt time.Time      `json:"updated_at"`
	DeletedAt gorm.DeletedAt `gorm:"index" json:"deleted_at"`
	Key       uint           `json:"key"`
	DiagramID uint           `gorm:"index" json:"diagram_id"`
}

Where a project can have multiple diagrams and a diagram can have multiple instances. But when I am running the DeleteProject function it is only deleting the Project and not the associated diagrams and instances.

How can I delete a project and it's associated diagrams and instances in this case?

答案1

得分: 2

我找到了一个解决方案,但我认为对于级联删除来说并不是最优的,至少解决了我的问题。我编写了以下代码:

首先是DeleteProject函数,其中我循环遍历所有的Diagrams并调用DeleteDiagram函数,最后在删除项目之前还清除了与该项目的所有关联。

//删除项目及其关联
func DeleteProject(db *gorm.DB, id uint) (Project, error) {
	project, err := GetProject(db, id)
	if err != nil {
		return Project{}, err
	}
	if len(project.Diagrams) > 0 {
		for _, projectDiagram := range project.Diagrams {
			_, err := DeleteDiagram(db, projectDiagram.ID)
			if err != nil {
				return Project{}, err
			}
		}
		db.Model(&project).Association("Diagrams").Clear()
	}
	if err := db.Delete(&project, id).Error; err != nil {
		return Project{}, err
	}
	return project, nil
}

DeleteDiagram函数也是类似的,只是针对Instances进行操作。

//删除图表及其关联
func DeleteDiagram(db *gorm.DB, id uint) (Diagram, error) {
	var diagram, err = GetDiagram(db, id)
	if err != nil {
		return Diagram{}, err
	}
	if len(diagram.Instances) > 0 {
		db.Model(&diagram).Association("Instances").Clear()
		for _, diagramInstance := range diagram.Instances {
			_, err := DeleteInstance(db, diagramInstance.ID)
			if err != nil {
				return Diagram{}, err
			}
		}
	}
	if err := db.Delete(&diagram).Error; err != nil {
		return Diagram{}, err
	}
	return diagram, nil
}

希望对你有帮助。

英文:

I found an solution, but I think it is not optimal for cascade delete, it solved my problem at least. I've coded the following:

First the DeleteProject function, where I loop over all Diagrams and call the DeleteDiagram function and finally I also clear all associations with this project before deleting the project.

//Delete a project and it's associations.
func DeleteProject(db *gorm.DB, id uint) (Project, error) {
	project, err := GetProject(db, id)
	if err != nil {
		return Project{}, err
	}
	if len(project.Diagrams) > 0 {
		for _, projectDiagram := range project.Diagrams {
			_, err := DeleteDiagram(db, projectDiagram.ID)
			if err != nil {
				return Project{}, err
			}
		}
		db.Model(&project).Association("Diagrams").Clear()
	}
	if err := db.Delete(&project, id).Error; err != nil {
		return Project{}, err
	}
	return project, nil
}

The DeleteDiagram does the same, but then with the Instances

//Delete a diagram and it's associations.
func DeleteDiagram(db *gorm.DB, id uint) (Diagram, error) {
	var diagram, err = GetDiagram(db, id)
	if err != nil {
		return Diagram{}, err
	}
	if len(diagram.Instances) > 0 {
		db.Model(&diagram).Association("Instances").Clear()
		for _, diagramInstance := range diagram.Instances {
			_, err := DeleteInstance(db, diagramInstance.ID)
			if err != nil {
				return Diagram{}, err
			}
		}
	}
	if err := db.Delete(&diagram).Error; err != nil {
		return Diagram{}, err
	}
	return diagram, nil
}

Hope it helps.

huangapple
  • 本文由 发表于 2021年6月10日 04:14:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/67911127.html
匿名

发表评论

匿名网友

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

确定