elunez/eladmin · error · BadRequestException

上级不能为自己

Error message

上级不能为自己

What it means

Thrown by DeptServiceImpl.update (line 130) on PUT /api/dept when the submitted pid equals the dept's own id — making the department its own parent. eladmin validates direct self-parenting before saving; deeper cycles (A→B→A) are NOT caught here and only surface later as broken tree queries.

Source

Thrown at eladmin-system/src/main/java/me/zhengjie/modules/system/service/impl/DeptServiceImpl.java:130

    @Transactional(rollbackFor = Exception.class)
    public void create(Dept resources) {
        deptRepository.save(resources);
        // 计算子节点数目
        resources.setSubCount(0);
        // 清理缓存
        updateSubCnt(resources.getPid());
        // 清理自定义角色权限的datascope缓存
        delCaches(resources.getPid());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Dept resources) {
        // 旧的部门
        Long oldPid = findById(resources.getId()).getPid();
        Long newPid = resources.getPid();
        if(resources.getPid() != null && resources.getId().equals(resources.getPid())) {
            throw new BadRequestException("上级不能为自己");
        }
        Dept dept = deptRepository.findById(resources.getId()).orElseGet(Dept::new);
        ValidationUtil.isNull( dept.getId(),"Dept","id",resources.getId());
        resources.setId(dept.getId());
        deptRepository.save(resources);
        // 更新父节点中子节点数目
        updateSubCnt(oldPid);
        updateSubCnt(newPid);
        // 清理缓存
        delCaches(resources.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Set<DeptDto> deptDtos) {
        for (DeptDto deptDto : deptDtos) {
            // 清理缓存
            delCaches(deptDto.getId());

View on GitHub (pinned to 55fbf70595)

Solutions

  1. Pick a different parent (or null for a root dept) and resubmit.
  2. Front end: filter the current node (and ideally its subtree) out of the parent options: options.filter(node => node.id !== form.id).
  3. If importing data, pre-validate pid != id and no ancestor loops before calling the API.

Example fix

// before
<el-cascader :options="deptTree" v-model="form.pid" /> // includes self
// after
<el-cascader :options="deptTree.filter(d => d.id !== form.id)" v-model="form.pid" />
Defensive patterns

Strategy: validation

Validate before calling

if (form.pid != null && form.pid === form.id) {
  notifyError('上级不能为自己');
  return;
}
await axios.put('/api/dept', form);

Type guard

const pidIsValid = (form) => form.pid == null || form.pid !== form.id;

Prevention

When it happens

Trigger: Editing a dept and selecting itself in the parent-dept tree picker; front-end defaulting the pid selector to the node being edited; migrating dept data where source ids and parent ids collide.

Common situations: Tree-select component not excluding the current node from selectable parents; admin drags a dept onto itself in a tree editor; hand-written SQL updates setting pid = id by accident.

Related errors


AI-assisted analysis of elunez/eladmin@55fbf70595 (2026-08-14). Data as JSON: /api/errors/0242b1486e1fb0ed. Report an issue: GitHub.