{"record":{"id":"8e3a389c25c71f93","repo":"hs-web/hsweb-framework","slug":"parentid","errorCode":"parentId","errorMessage":"子节点ID不能与父节点ID相同","messagePattern":"子节点ID不能与父节点ID相同","errorType":"validation","errorClass":"ValidationException","httpStatus":400,"severity":"error","filePath":"hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java","lineNumber":114,"sourceCode":"     *\n     * @return 节点层级\n     */\n    void setLevel(Integer level);\n\n    /**\n     * 获取所有子节点,默认情况下此字段只会返回null.可以使用{@link TreeSupportEntity#list2tree(Collection, BiConsumer)}将\n     * 列表结构转为树形结构\n     *\n     * @param <T> 当前实体类型\n     * @return 自己节点\n     */\n    <T extends TreeSupportEntity<PK>> List<T> getChildren();\n\n    @Override\n    default void tryValidate(Class<?>... groups) {\n        Entity.super.tryValidate(groups);\n        if (getId() != null && Objects.equals(getId(), getParentId())) {\n            throw new ValidationException(\"parentId\", \"子节点ID不能与父节点ID相同\");\n        }\n    }\n\n    /**\n     * 根据path获取父节点的path\n     *\n     * @param path path\n     * @return 父节点path\n     */\n    static String getParentPath(String path) {\n        if (path == null || path.length() < 4) {\n            return null;\n        }\n        return path.substring(0, path.length() - 5);\n    }\n\n    static <T extends TreeSupportEntity> void forEach(Collection<T> list, Consumer<T> consumer) {\n        Queue<T> queue = new LinkedList<>(list);","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/hs-web/hsweb-framework/blob/b2cfc85a57c70bf5b5cf6e7edae2d37102652ec8/hsweb-commons/hsweb-commons-api/src/main/java/org/hswebframework/web/api/crud/entity/TreeSupportEntity.java#L96-L132","documentation":"TreeSupportEntity.tryValidate() adds a tree-specific rule on top of standard bean validation: a node's id must never equal its parentId, which would create a self-referencing cycle. It throws ValidationException with field 'parentId' and message '子节点ID不能与父节点ID相同' (child ID must not equal parent ID).","triggerScenarios":"Saving or updating a tree entity (e.g. via CRUD save/update endpoints) where entity.getId() is not null and equals entity.getParentId().","commonSituations":"Client sends the same value in both id and parentId fields; frontend form copies id into parentId for root nodes; batch import where the parent column is misaligned; an update that re-parents a node to itself.","solutions":["Ensure parentId is null for root nodes instead of copying the node's own id.","Fix the client/form so parentId only contains a real, distinct parent identifier.","Before saving, validate that id != parentId and reject or correct the payload.","For re-parenting, verify the target parent is not the node itself (or a descendant) to avoid cycles."],"exampleFix":"// before\n{\"id\":\"100\",\"parentId\":\"100\",\"name\":\"dept\"} // self-parent\n// after\n{\"id\":\"100\",\"parentId\":null,\"name\":\"dept\"} // root node","handlingStrategy":"validation","validationCode":"if (entity.getId() != null && entity.getId().equals(entity.getParentId())) {\n    throw new ValidationException(\"parentId\", \"子节点ID不能与父节点ID相同\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    crudService.save(entity);\n} catch (ValidationException e) {\n    if (\"parentId\".equals(e.getField())) {\n        // clear parentId (treat as root) or reject, then retry once\n        entity.setParentId(null);\n        crudService.save(entity);\n    } else {\n        throw e;\n    }\n}","preventionTips":["Treat parentId=null as the convention for root nodes in clients and imports.","Validate id != parentId (and no descendant cycles) before calling save/update.","Sanitize batch imports so the parent column cannot carry the row's own id.","Add form-level checks so the UI never copies id into parentId."],"tags":["java","validation","tree","entity"],"backgroundTag":"schema-validation-failed","analyzedSha":"b2cfc85a57c70bf5b5cf6e7edae2d37102652ec8","analyzedAt":"2026-09-13T09:05:02.172Z","contentChangedAt":"2026-09-13T09:05:02.172Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}