Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2004-2022, University of Oslo
* Copyright (c) 2004-2026, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -65,6 +65,32 @@ public interface EnrollmentMapper extends PreheatMapper<Enrollment> {
@Mapping(target = "status")
Enrollment map(Enrollment enrollment);

/**
* Same as {@link #map(Enrollment)} but without {@code notes}, which is a lazy collection. Mapping
* it would force a query to load it. Use this for enrollments that are only ever read for their
* identifiers (e.g. the synthetic enrollment preheated for WITHOUT_REGISTRATION programs), never
* converted or persisted.
*/
@Named("mapWithoutNotes")
@BeanMapping(ignoreByDefault = true)
@Mapping(target = "id")
@Mapping(target = "uid")
@Mapping(target = "code")
@Mapping(target = "user")
@Mapping(target = "completedBy")
@Mapping(target = "completedDate")
@Mapping(target = "program", qualifiedByName = "program")
@Mapping(target = "trackedEntity")
@Mapping(target = "organisationUnit")
@Mapping(target = "created")
@Mapping(target = "occurredDate")
@Mapping(target = "enrollmentDate")
@Mapping(target = "deleted")
@Mapping(target = "createdByUserInfo")
@Mapping(target = "lastUpdatedByUserInfo")
@Mapping(target = "status")
Enrollment mapWithoutNotes(Enrollment enrollment);

@Named("program")
@BeanMapping(ignoreByDefault = true)
@Mapping(target = "id")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2004-2022, University of Oslo
* Copyright (c) 2004-2026, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -61,10 +61,13 @@
programsWithoutRegistration = programStore.getByType(ProgramType.WITHOUT_REGISTRATION);
}
if (!programsWithoutRegistration.isEmpty()) {
// This enrollment is only ever used as an FK reference for events (it is never converted
// or persisted), so its notes are never read: map without them to avoid an unnecessary
// lazy-load query per WITHOUT_REGISTRATION program on every import.
List<Enrollment> enrollments =
DetachUtils.detach(
EnrollmentMapper.INSTANCE,
enrollmentStore.getByPrograms(programsWithoutRegistration));
enrollmentStore.getByPrograms(programsWithoutRegistration).stream()
.map(EnrollmentMapper.INSTANCE::mapWithoutNotes)
.collect(Collectors.toList());

Check warning on line 70 in dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/preheat/supplier/EnrollmentSupplier.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this usage of 'Stream.collect(Collectors.toList())' with 'Stream.toList()' and ensure that the list is unmodified.

See more on https://sonarcloud.io/project/issues?id=dhis2_dhis2-core&issues=AaBbpOf99tP7Bty8R_yb&open=AaBbpOf99tP7Bty8R_yb&pullRequest=25006

enrollments.forEach(
e -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2004-2022, University of Oslo
* Copyright (c) 2004-2026, University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -31,6 +31,9 @@
import static org.hisp.dhis.program.ProgramType.WITH_REGISTRATION;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.google.common.collect.Lists;
Expand Down Expand Up @@ -149,6 +152,24 @@ void verifySupplier() {
preheat.getEnrollmentsWithoutRegistration(programWithoutRegistration.getUid()));
}

@Test
void verifySupplierDoesNotAccessNotesOfEnrollmentWithoutRegistration() {
// On a real (Hibernate-backed) Enrollment, calling getNotes() on an entity that hasn't
// had its notes collection initialized yet triggers a lazy-load query. This enrollment is
// only ever used by the importer as an FK reference for events, never converted or
// persisted, so its notes must never be read during preheat.
Enrollment spiedEnrollmentWithoutRegistration = spy(enrollmentWithoutRegistration);
when(enrollmentStore.getByPrograms(Lists.newArrayList(programWithoutRegistration)))
.thenReturn(List.of(spiedEnrollmentWithoutRegistration));
preheat.put(
TrackerIdSchemeParam.UID,
Lists.newArrayList(programWithRegistration, programWithoutRegistration));

this.supplier.preheatAdd(params, preheat);

verify(spiedEnrollmentWithoutRegistration, never()).getNotes();
}

private void assertEnrollmentInPreheat(Enrollment expected, Enrollment actual) {
assertEquals(expected.getUid(), actual.getUid());
assertEquals(expected.getProgram().getUid(), actual.getProgram().getUid());
Expand Down
Loading