feat: TrackedEntity JDBC insert [DHIS2-21378]#24027
Merged
Merged
Conversation
f858d0f to
831dd36
Compare
831dd36 to
6f5b5db
Compare
muilpp
approved these changes
Jun 1, 2026
| * one id per CREATE entity in a single round-trip and assigns the id before staging so the flush | ||
| * path can emit a multi-row INSERT. | ||
| */ | ||
| protected abstract String sequenceName(); |
Contributor
There was a problem hiding this comment.
could we not make this one return null by default and make TrackedEntityPersister override it? this way we would get rid of the boilerplate code in the other persisters
Contributor
Author
There was a problem hiding this comment.
I just changed to be this way because this is the skeleton for next steps.
Every persister will need to implement this, so there will be no null returned in the end
ameenhere
approved these changes
Jun 2, 2026
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
Phase 4a of the Hibernate→JDBC tracker bundle persist migration (DHIS2-21378): replace the Hibernate-driven insert path for
TrackedEntitywith a JDBC multi-row INSERT, while leaving allother entity types and TEAVs on
EntityManageruntil their respective phases.trackedentityinstance_sequencein a single round-trip (select nextval(seq) from generate_series(1, ?)), and assigns the id to the converted DTO beforestaging so any TEAV/changelog code reading
convertedDto.getId()sees the final value.EntityWriteBatch.flush(EntityManager)withflush(EntityManager, Connection). TrackedEntity inserts now go through a chunked multi-row JDBC INSERT (128 rows / statement, 15columns including
ST_GeomFromText(...,4326)and::jsonbuserinfo); everything else still delegates toem.persist/em.merge.AbstractTrackerPersister.sequenceName()as the per-subclass opt-in: onlyTrackedEntityPersisterreturns"trackedentityinstance_sequence"; Enrollment / TrackerEvent /SingleEvent / Relationship return
nulland keep their current behavior.getTrackedEntityAttributeValueMapto gate the "load existing TEAVs" JPQL onbatch.isStagedAsInsert(te)instead ofte.getId() == 0, because pre-allocated ids are no longer areliable transient marker.
TrackerImportReportTestfromH2ControllerIntegrationTestBasetoPostgresControllerIntegrationTestBasesinceST_GeomFromTextand::jsonbare PostgreSQL-only.Design notes
batch.flush(em, conn)runs JDBC TE inserts first, thenem.flush()(TEAVs, other types), then changelog inserts. TEAVs persisted viaem.persistreference a TE thatis not in the persistence context but carries a pre-allocated id; Hibernate writes the FK from
te.getId()without managing the TE. Changelog FKs see the TE row because both run on thesame Spring-bound connection inside one transaction.
sequenceName()is concatenated into the SQL (not bound) because PostgreSQL'snextvaltakes aregclass. Safe — the value is a hardcoded constant oneach persister subclass, never user input.
bindTrackedEntityRowthrows if it encounters a staged TE withid == 0, andassignIdthrowsIllegalStateExceptionfor any DTO type the dispatch doesn't yethandle — future phases will plug in additional types.