diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementGroupSetDimension.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementGroupSetDimension.java index cc7bedc18f9e..3ff61547fd30 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementGroupSetDimension.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/dataelement/DataElementGroupSetDimension.java @@ -34,8 +34,23 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.ForeignKey; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OrderColumn; +import jakarta.persistence.Table; import java.util.ArrayList; import java.util.List; +import org.hibernate.annotations.Cache; +import org.hibernate.annotations.CacheConcurrencyStrategy; import org.hisp.dhis.common.BaseIdentifiableObject; import org.hisp.dhis.common.DimensionalEmbeddedObject; import org.hisp.dhis.common.DxfNamespaces; @@ -45,14 +60,37 @@ /** * @author Lars Helge Overland */ +@Entity +@Table(name = "dataelementgroupsetdimension") +@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) @JacksonXmlRootElement( localName = "dataElementGroupSetDimension", namespace = DxfNamespaces.DXF_2_0) public class DataElementGroupSetDimension implements DimensionalEmbeddedObject { + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE) + @Column(name = "dataelementgroupsetdimensionid") private int id; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn( + name = "dataelementgroupsetid", + foreignKey = @ForeignKey(name = "fk_dimension_dataelementgroupsetid")) private DataElementGroupSet dimension; + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable( + name = "dataelementgroupsetdimension_items", + joinColumns = + @JoinColumn( + name = "dataelementgroupsetdimensionid", + foreignKey = @ForeignKey(name = "fk_dimension_items_dataelementgroupsetdimensionid")), + inverseJoinColumns = + @JoinColumn( + name = "dataelementgroupid", + foreignKey = @ForeignKey(name = "fk_dimension_items_dataelementgroupid"))) + @OrderColumn(name = "sort_order") + @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE) private List items = new ArrayList<>(); public int getId() { diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataelement/hibernate/DataElementGroupSetDimension.hbm.xml b/dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataelement/hibernate/DataElementGroupSetDimension.hbm.xml deleted file mode 100644 index b1a4047fbbe0..000000000000 --- a/dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/dataelement/hibernate/DataElementGroupSetDimension.hbm.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/visualization/DefaultVisualizationServiceTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/visualization/DefaultVisualizationServiceTest.java index 436117082c31..e7cfceca09c3 100644 --- a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/visualization/DefaultVisualizationServiceTest.java +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/visualization/DefaultVisualizationServiceTest.java @@ -32,9 +32,16 @@ import static org.hisp.dhis.visualization.Icon.IconType.DATA_ITEM; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import java.util.List; import java.util.Set; +import org.hisp.dhis.common.IdentifiableObjectManager; +import org.hisp.dhis.dataelement.DataElementGroup; +import org.hisp.dhis.dataelement.DataElementGroupSet; +import org.hisp.dhis.dataelement.DataElementGroupSetDimension; import org.hisp.dhis.test.integration.PostgresIntegrationTestBase; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; @@ -43,6 +50,7 @@ @Transactional class DefaultVisualizationServiceTest extends PostgresIntegrationTestBase { @Autowired private VisualizationService visualizationService; + @Autowired private IdentifiableObjectManager manager; @Test void testPostWithIconsObject() { @@ -67,4 +75,48 @@ private Visualization createVisualization(String name) { visualization.setName(name); return visualization; } + + // ------------------------------------------------------------------------- + // JPA migration verification (DataElementGroupSetDimension HBM -> annotations) + // ------------------------------------------------------------------------- + + @Test + @DisplayName( + "JPA: DataElementGroupSetDimension (dimension + ordered items) round-trips through the " + + "still-HBM-mapped Visualization owner") + void testJpaDataElementGroupSetDimensionRoundTrip() { + DataElementGroup degA = createDataElementGroup('A'); + DataElementGroup degB = createDataElementGroup('B'); + DataElementGroup degC = createDataElementGroup('C'); + manager.save(degA); + manager.save(degB); + manager.save(degC); + + DataElementGroupSet degs = createDataElementGroupSet('S'); + manager.save(degs); + + DataElementGroupSetDimension dimension = new DataElementGroupSetDimension(); + dimension.setDimension(degs); + dimension.setItems(List.of(degC, degA, degB)); + + Visualization visualization = createVisualization('V'); + visualization.addDataElementGroupSetDimension(dimension); + + long id = visualizationService.save(visualization); + + clearSession(); // force reload from DB + + Visualization reloaded = visualizationService.getVisualization(id); + assertNotNull(reloaded); + assertEquals(1, reloaded.getDataElementGroupSetDimensions().size()); + + DataElementGroupSetDimension reloadedDimension = + reloaded.getDataElementGroupSetDimensions().get(0); + assertEquals(degs.getUid(), reloadedDimension.getDimension().getUid()); + + // @OrderColumn must preserve insertion order, not just membership. + List itemUids = + reloadedDimension.getItems().stream().map(DataElementGroup::getUid).toList(); + assertEquals(List.of(degC.getUid(), degA.getUid(), degB.getUid()), itemUids); + } }