fix(document): add trainingLabels to Document.full entity graph (#642) #644
Reference in New Issue
Block a user
Delete Branch "fix/issue-642-training-labels-entity-graph"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #642
Summary
Add
trainingLabelsto theDocument.full@NamedEntityGraph.trainingLabelswas switched fromEAGERtoLAZYin #467 but not added toDocument.full.DocumentRepository.findById()uses@EntityGraph("Document.full"), which loads sender/receivers/tags eagerly within the transaction — buttrainingLabelsis left uninitialized. The Hibernate session closes whengetDocumentById()returns. When Jackson serializes the response body, it accessestrainingLabelswith no session →LazyInitializationException→ HTTP 500.One-line diff:
Test plan
GET /api/documents/{id}returns 200 (was 500) for a document with training labelsDocumentLazyLoadingTest— the test already exercisesgetDocumentByIdand checks no lazy-load outside sessionLazyInitializationExceptionentries in GlitchTip / Grafana for the document endpoint🏛️ Markus Keller — Software Architect
Verdict: ✅ Approved
The fix correctly identifies and resolves the root cause at the right layer.
Root cause analysis:
Commit
56bcbcddswitchedDocument.trainingLabelsfromEAGERtoLAZYas part of the @mention PR. The@NamedEntityGraph("Document.full")was not updated to includetrainingLabels. WhenDocumentService.getDocumentById()loads the entity with thefullgraph, the session closes at method exit. Jackson then serializestrainingLabelsoutside the session, triggeringLazyInitializationException.Why this fix is correct:
@NamedAttributeNode("trainingLabels")toDocument.fulltells Hibernate to JOIN-fetch the collection in the same query, making it available post-session.Document.listcorrectly omits it — list view does not need training labels, so the N+1 guard holds.EAGER(which would affect all load paths) or wrapping the service method in a larger transaction (which would push session lifetime concerns into the wrong layer).The pattern is established and consistent:
Document.fullexists precisely for this purpose. This is a minimal, correct fix that follows existing conventions. No architectural concerns.👨💻 Felix Brandt — Senior Fullstack Developer
Verdict: ✅ Approved
Single-line fix, correct, minimal, no collateral changes.
What I verified:
Document.fullbefore this PR:sender,receivers,tags— used bygetDocumentById()via@EntityGraph("Document.full")in the repository.trainingLabelsis@ElementCollection(fetch = FetchType.LAZY)on aSet<TrainingLabel>.Document.listomits it — correct, list views don't render training labels.One thing to watch for in future PRs:
The regression pattern here is: "change a field's fetch type without auditing all entity graphs that touch the entity." This is easy to miss. Worth adding a comment on the
trainingLabelsfield itself or in theDocument.fullgraph to make the coupling explicit — but I'd call that a suggestion, not a blocker.Suggestion (non-blocking):
A comment on
Document.fulllisting what it's used for (full detail view) would help the next person adding a new lazy field know they should check both graphs:Up to you whether that comment adds value.
🛠️ Tobias Wendt — DevOps / Infrastructure
Verdict: ✅ Approved
Pure Java entity change — no infrastructure, compose, or deployment config touched. No deployment concerns.
The fix is self-contained to the backend artifact. The next nightly build will pick it up automatically. No env vars, no volume mounts, no network config affected.
LGTM from infra perspective.
📋 Elicit — Requirements Engineer
Verdict: ✅ Approved
Checking against issue #642 requirements:
trainingLabelsnow loaded within sessionDocument.fullentity graphThe fix addresses exactly what was described. No scope creep, no unrelated cleanup.
The suggested deploy order from PR #643 (merge observability first, then this PR) means the fix can be validated through GlitchTip absence — error disappears after merge. That's a clean acceptance criterion.
🔒 Nora "NullX" Steiner — Security Expert
Verdict: ✅ Approved
The change adds
trainingLabelsto theDocument.fullentity graph. Security review:trainingLabelsis an@ElementCollectionofTrainingLabelenum values on the sameDocumententity. It is already part of the entity's data model and was accessible before the LAZY regression.No security concerns. The fix is a pure JPA session boundary correction.
🧪 Sara Holt — QA / Tester
Verdict: ⚠️ Approved with concerns
The fix is correct, but there is no regression test to prevent this from silently breaking again.
What happened: A prior PR (
56bcbcdd) changedtrainingLabelsfromEAGERtoLAZYwithout updatingDocument.full. The document detail page then 500'd. No existing test caught this.Missing test (non-blocking suggestion):
An integration or
@DataJpaTestslice test forDocumentService.getDocumentById()that:Documentwith a non-emptytrainingLabelssetgetDocumentById()document.getTrainingLabels()is accessible (non-null, correct size) — outside the service method, simulating what Jackson does during serializationWithout this, the next PR that changes a fetch type on
Documentcould introduce the same regression undetected.Manual test plan for staging:
This is a suggestion — not a blocker for merging. The fix is correct and the issue is live in production.
🎨 Leonie Voss — UI / UX Expert
Verdict: ✅ Approved
This fix restores the document detail page to a working state — which was previously throwing a 500 error for users. From a UI perspective, the expected outcome is that the page loads again without an error.
No frontend code changed. No visual regressions expected.
LGTM.