Aias00 opened a new issue, #7772:
URL: https://github.com/apache/shenyu/issues/7772

   ### Current behavior
   
   `TagServiceImpl.update()` creates a partial TagDO from the DTO without 
`ext`. It then calls `updateSubTags()`, which replaces the edited node in its 
working map with another partial object lacking the persisted extension state. 
Descendants are rebuilt from this incomplete parent.
   
   On a parent move, the edited node's final selective update changes 
`parent_tag_id` but leaves its old `ext` in the database because the new 
object's ext is null. Descendants meanwhile get a truncated extension chain 
that contains the edited node but omits its old/new ancestors.
   
   ### Locations / actual entry
   
   - 
[TagServiceImpl.java:95–100,172–240](https://github.com/apache/shenyu/blob/66d7d954ca37d651a5ad916f988a8081157a7ab4/shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/TagServiceImpl.java#L95)
   - 
[TagDO.buildTagDO():158–176](https://github.com/apache/shenyu/blob/66d7d954ca37d651a5ad916f988a8081157a7ab4/shenyu-admin/src/main/java/org/apache/shenyu/admin/model/entity/TagDO.java#L158)
 does not populate ext.
   - 
[tag-sqlmap.xml:151–174](https://github.com/apache/shenyu/blob/66d7d954ca37d651a5ad916f988a8081157a7ab4/shenyu-admin/src/main/resources/mappers/tag-sqlmap.xml#L151)
 selectively retains an old ext when the update supplies null.
   - `PUT /tag/id/{id}` calls `tagService.update(tagDTO)`.
   
   ### Reproduction / validation
   
   A Java probe compiled the current service and TagDO, created root tags A/B, 
C under A, and D under C through the actual service create methods. It then 
moved C under B using actual `update()`.
   
   Mapper I/O was replaced by an in-memory store with copy-on-read and the same 
selective-update semantics as the XML. The service's extension construction and 
recursion ran unchanged:
   
   ```text
   BEFORE C.ext=[A] D.ext=[C, A]
   AFTER C.parent=B C.ext=[A] D.ext=[C]
   ```
   
   Expected: C's extension ancestry refers to B, and D's ancestry is C → B. The 
before state is the passing create control. An independent reviewer confirmed 
the partial-parent replacement and selective persistence behavior. No deployed 
database or frontend was used.
   
   ### Impact / scope
   
   Successful edits can leave `parentTagId` and the API's serialized extension 
ancestry inconsistent, and remove ancestor metadata from descendants. Even a 
rename of a non-root node can rebuild descendants from a parent object missing 
its previous ext. This report does not claim a specific Swagger pull failure or 
data loss beyond the observed extension state.
   
   ### Suggested fix
   
   Merge the update with the persisted edited node, rebuild its own extension 
from the effective new parent when needed, and use that complete node as the 
recursion parent. Persist parent/descendant extension state consistently within 
the existing transaction while preserving unrelated extension fields.
   
   ### Related existing work
   
   #6552 fixed missing transaction rollback around recursive updates. This 
mismatch occurs when every write succeeds, so adding a transaction does not fix 
it. #6520 concerns creating a tag whose parent does not exist. Current-tag 
ancestry reconstruction is a separate deterministic correctness defect.
   
   
   ### Reviewed revision
   
   Apache ShenYu 2.7.2-SNAPSHOT, 
`master@66d7d954ca37d651a5ad916f988a8081157a7ab4`. P2 / Medium; high 
confidence. Unit-test and CI issue categories excluded.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to