{"record":{"id":"98244e077dfd9b3e","repo":"flipped-aurora/gin-vue-admin","slug":"error-98244e","errorCode":null,"errorMessage":"父部门不能是自己","messagePattern":"父部门不能是自己","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/service/system/sys_department.go","lineNumber":109,"sourceCode":"\treturn nil\n}\n\n// CreateSysDepartment 创建部门并自动维护祖级链\nfunc (s *SysDepartmentService) CreateSysDepartment(ctx context.Context, dept *system.SysDepartment) (err error) {\n\tancestors, err := s.buildAncestors(ctx, dept.ParentId)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdept.Ancestors = ancestors\n\tdept.Children = nil\n\treturn global.GVA_DB.WithContext(ctx).Create(dept).Error\n}\n\n// UpdateSysDepartment 更新部门, 若父部门变更则重算本节点祖级链\n// 注: 子孙节点的祖级链重算(部门移动)属后续阶段, 此处仅保证本节点正确\nfunc (s *SysDepartmentService) UpdateSysDepartment(ctx context.Context, dept *system.SysDepartment) (err error) {\n\tif dept.ParentId == dept.ID {\n\t\treturn errors.New(\"父部门不能是自己\")\n\t}\n\tancestors, err := s.buildAncestors(ctx, dept.ParentId)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn global.GVA_DB.WithContext(ctx).Model(&system.SysDepartment{}).Where(\"id = ?\", dept.ID).Updates(map[string]interface{}{\n\t\t\"name\":      dept.Name,\n\t\t\"parent_id\": dept.ParentId,\n\t\t\"ancestors\": ancestors,\n\t\t\"sort\":      dept.Sort,\n\t\t\"leader_id\": dept.LeaderId,\n\t\t\"status\":    dept.Status,\n\t}).Error\n}\n\n// DeleteSysDepartment 删除部门, 存在子部门或已有用户归属时禁止删除\nfunc (s *SysDepartmentService) DeleteSysDepartment(ctx context.Context, id uint) (err error) {\n\tif id == 0 {","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/service/system/sys_department.go#L91-L127","documentation":"UpdateSysDepartment rejects an update where the department's ParentId equals its own ID, which would create a self-referencing cycle in the ancestor chain. The guard is a plain equality check before recomputing ancestors.","triggerScenarios":"Calling UpdateSysDepartment with a SysDepartment whose ParentId == ID, typically from an edit form where the user selected the department itself as its parent.","commonSituations":"Department tree UI allowing all nodes (including self) in the parent selector; API consumers constructing update payloads programmatically and copying ID into ParentId.","solutions":["Choose a different parent department that is not the record itself","In the frontend parent selector, exclude the node being edited (and ideally its descendants) from options","If no parent change is intended, leave ParentId unchanged"],"exampleFix":"// before (frontend)\nconst options = allDepartments\n// after\nconst options = allDepartments.filter(d => d.ID !== editingDept.ID)","handlingStrategy":"validation","validationCode":"if dept.ParentId == dept.ID {\n    return errors.New(\"department cannot be its own parent\")\n}","typeGuard":null,"tryCatchPattern":"if err := deptService.UpdateSysDepartment(ctx, dept); err != nil {\n    if err.Error() == \"父部门不能是自己\" {\n        // prompt user to pick a different parent\n    }\n    return err\n}","preventionTips":["In the parent selector, filter out the node being edited","Disable 'save' when the selected parent equals the current node","Prefer leaving ParentId unchanged when no move is intended"],"tags":["department","validation","cycle-detection","go"],"backgroundTag":"circular-reference-detected","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}