2024-08-30
Go & 后端
00

目录

1 删除分类接口

MisakaOJ项目,第四次记录内容

1 删除分类接口

该接口按情况分,需要一次性彻底删除的(包括分类下的所有题目全部删除和所有子分类的父级id置零)的情况和只删除分类本身(如果分类下有东西就停止删除)的情况要分别处理。

提示

注意,gorm的ErrRecordNotFound错误只会在传入的是单个结构体或者结构体指针才会触发,如果传入的是切片则不会触发该错误。该结论对FirstLastFind等函数都有效。

另外,FindFirst差距很小,First可以视作按主键排序后再加一个Limit(1)Find

go
// First finds the first record ordered by primary key, matching given conditions conds func (db *DB) First(dest interface{}, conds ...interface{}) (tx *DB) { tx = db.Limit(1).Order(clause.OrderByColumn{ Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey}, }) if len(conds) > 0 { if exprs := tx.Statement.BuildCondition(conds[0], conds[1:]...); len(exprs) > 0 { tx.Statement.AddClause(clause.Where{Exprs: exprs}) } } tx.Statement.RaiseErrorOnNotFound = true tx.Statement.Dest = dest return tx.callbacks.Query().Execute(tx) }

提示

gorm对于启用了gorm.Model的模型,所使用的都是软删除。即删除时并不真正删除数据,而是在delete_at字段下留下删除时间。如果要真的将某条记录删除,需要这样:

go
err := DB.Unscoped().Delete(&Question{}, "identity = ?", identity).Error if err != nil { // 处理错误 }

Handler层:

go
// RemoveCategory // @Tags 管理员接口 // @Summary 删除分类信息 // @Param authorization header string true "authorization" // @Param category_id query int true "category_id" // @Param is_cascade query bool true "is_cascade" // @Success 200 {data} json "{"code": "200", "message": ""}" // @Router /admin/remove_category [delete] func RemoveCategory(c *gin.Context) { categoryId, e := strconv.Atoi(c.Query("category_id")) if e != nil { ErrorHandler(c, constants.ParameterParseErr.Error()+"category_id: "+e.Error()) return } if categoryId < 0 { ErrorHandler(c, constants.ParameterParseErr.Error()+"category_id: less than 0") return } // 把isCascade参数解析出来 var isCascade bool isCascadeString := c.Query("is_cascade") if isCascadeString == "" { ErrorHandler(c, constants.ParameterMissingErr.Error()+"is_cascade") return } if isCascadeString == "true" { isCascade = true } else if isCascadeString == "false" { isCascade = false } else { ErrorHandler(c, constants.ParameterParseErr.Error()+"is_cascade") return } // 先把要改的Category查出来 deleteCategory := &models.Category{} tx := models.GetCategoryByColumn("id", categoryId) e = tx.First(deleteCategory).Error if e != nil { if errors.Is(e, gorm.ErrRecordNotFound) { ErrorHandler(c, constants.CategoryNotExistErr.Error()+"id "+string(rune(categoryId))) return } ErrorHandler(c, errors.Join(constants.DataBaseQueryErr, e).Error()) return } // 把相联的题目和子分类全查出来 // 先查子分类 childrenCategory := make([]*models.Category, 0) tx = models.GetCategoryByColumn("parent_id", deleteCategory.ID) e = tx.Find(&childrenCategory).Error // find first 等函数传入的是数组时 不会报ErrRecordNotFound if e != nil { ErrorHandler(c, errors.Join(constants.DataBaseQueryErr, e).Error()) return } // 查题目 relatedQuestion := make([]*models.Question, 0) tx = models.GetQuestionList("", strconv.Itoa(int(deleteCategory.ID))) e = tx.Preload("TestCases").Find(&relatedQuestion).Error if e != nil { ErrorHandler(c, errors.Join(constants.DataBaseQueryErr, e).Error()) return } // // 开始删除 if isCascade { // 要级联删除所有信息 相关问题全部删除 子分类的父级id置零 // 先将子分类的父级id置零 for i := range childrenCategory { childrenCategory[i].ParentId = 0 e = models.ModifyCategory(childrenCategory[i]) if e != nil { ErrorHandler(c, errors.Join(constants.DataBaseUpdateErr, e).Error()) return } } // 再删除相关问题 for i := range relatedQuestion { // 删除问题分类关联表里的记录 e = models.DeleteQCByQuestionId(relatedQuestion[i].ID) if e != nil { ErrorHandler(c, errors.Join(constants.DataBaseUpdateErr, e).Error()) return } // 删除对应的测试用例 e = models.DeleteTestCaseByQuestionId(relatedQuestion[i].Identity) if e != nil { ErrorHandler(c, errors.Join(constants.DataBaseUpdateErr, e).Error()) return } // 删除对应的提交记录 e = models.DeleteSubmitByQuestionId(relatedQuestion[i].Identity) if e != nil { ErrorHandler(c, errors.Join(constants.DataBaseUpdateErr, e).Error()) return } // 最后删除问题 e = models.DeleteQuestion(relatedQuestion[i]) if e != nil { ErrorHandler(c, errors.Join(constants.DataBaseUpdateErr, e).Error()) return } } } else { // 仅删除分类时 必须检查 if len(childrenCategory) != 0 || len(relatedQuestion) != 0 { // 不能删除 ErrorHandler(c, constants.CategoryCanNotCascadeDelErr.Error()) return } } // 最后删除分类 e = models.DeleteCategory(deleteCategory) if e != nil { ErrorHandler(c, errors.Join(constants.DataBaseDeleteErr, e).Error()) return } c.JSON(http.StatusOK, gin.H{ "code": 200, "message": "Delete Category Successfully! ", }) }

对应的几个Model层函数,就挑两个作为示例:

go
// DeleteCategory 删除分类 传入的category只能是有数据的 func DeleteCategory(category *Category) error { return DB.Delete(category).Error } func DeleteQCByQuestionId(questionId uint) error { return DB.Where("question_id = ?", questionId).Delete(&QuestionCategory{}).Error }

本文作者:御坂19327号

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!