diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/hibernate/HibernateDataValueStore.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/hibernate/HibernateDataValueStore.java index f4013eadba2a..b7eb7e0e8d46 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/hibernate/HibernateDataValueStore.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/datavalue/hibernate/HibernateDataValueStore.java @@ -185,13 +185,22 @@ public DataValue getSoftDeletedDataValue(DataValue dataValue) { dataValue.setPeriod(storedPeriod); - CriteriaBuilder builder = getCriteriaBuilder(); + String sql = + "select * from datavalue where dataelementid = :deid\n" + + "and periodid = :periodid\n" + + "and attributeoptioncomboid = :attributeOptionCombo\n" + + "and categoryoptioncomboid = :categoryOptionCombo\n" + + "and sourceid = :sourceid\n" + + "and deleted is true"; return getSingleResult( - builder, - newJpaParameters() - .addPredicate(root -> builder.equal(root, dataValue)) - .addPredicate(root -> builder.equal(root.get(DELETED), true))); + getSession() + .createNativeQuery(sql, DataValue.class) + .setParameter("deid", dataValue.getDataElement().getId()) + .setParameter("periodid", storedPeriod.getId()) + .setParameter("attributeOptionCombo", dataValue.getAttributeOptionCombo().getId()) + .setParameter("categoryOptionCombo", dataValue.getCategoryOptionCombo().getId()) + .setParameter("sourceid", dataValue.getSource().getId())); } @Override diff --git a/dhis-2/dhis-support/dhis-support-hibernate/src/main/java/org/hisp/dhis/hibernate/HibernateGenericStore.java b/dhis-2/dhis-support/dhis-support-hibernate/src/main/java/org/hisp/dhis/hibernate/HibernateGenericStore.java index 80b1761a6269..bf63dcca9148 100644 --- a/dhis-2/dhis-support/dhis-support-hibernate/src/main/java/org/hisp/dhis/hibernate/HibernateGenericStore.java +++ b/dhis-2/dhis-support/dhis-support-hibernate/src/main/java/org/hisp/dhis/hibernate/HibernateGenericStore.java @@ -236,6 +236,16 @@ protected V getSingleResult(TypedQuery typedQuery) { return list != null && !list.isEmpty() ? list.get(0) : null; } + protected V getSingleResult(NativeQuery nativeQuery) { + List list = nativeQuery.getResultList(); + + if (list != null && list.size() > 1) { + throw new NonUniqueResultException("More than one entity found for query"); + } + + return list != null && !list.isEmpty() ? list.get(0) : null; + } + /** * Get List objects returned by executable TypedQuery * diff --git a/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/datavalue/DataValueStoreTest.java b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/datavalue/DataValueStoreTest.java new file mode 100644 index 000000000000..986aef4fcc45 --- /dev/null +++ b/dhis-2/dhis-test-integration/src/test/java/org/hisp/dhis/datavalue/DataValueStoreTest.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2004-2024, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.datavalue; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.google.common.collect.Sets; +import java.util.Date; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import org.hisp.dhis.category.CategoryOption; +import org.hisp.dhis.category.CategoryOptionCombo; +import org.hisp.dhis.common.ValueType; +import org.hisp.dhis.dataelement.DataElement; +import org.hisp.dhis.organisationunit.OrganisationUnit; +import org.hisp.dhis.period.Period; +import org.hisp.dhis.period.PeriodType; +import org.hisp.dhis.period.PeriodTypeEnum; +import org.hisp.dhis.test.integration.SingleSetupIntegrationTestBase; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +class DataValueStoreTest extends SingleSetupIntegrationTestBase { + private @PersistenceContext EntityManager manager; + @Autowired private DataValueStore dataValueStore; + + @Test + void testGetSoftDeletedDataValue() { + DataValue dataValue = createDataValue(); + dataValueStore.addDataValue(dataValue); + dataValue.setDeleted(true); + dataValueStore.updateDataValue(dataValue); + DataValue deletedDataValue = dataValueStore.getSoftDeletedDataValue(dataValue); + assertEquals(dataValue.getDataElement().getId(), deletedDataValue.getDataElement().getId()); + assertEquals(dataValue.getSource().getId(), deletedDataValue.getSource().getId()); + assertEquals( + dataValue.getCategoryOptionCombo().getId(), + deletedDataValue.getCategoryOptionCombo().getId()); + assertEquals( + dataValue.getAttributeOptionCombo().getId(), + deletedDataValue.getAttributeOptionCombo().getId()); + assertEquals(dataValue.getValue(), deletedDataValue.getValue()); + } + + private DataValue createDataValue() { + DataElement dataElement = createDataElement('A'); + dataElement.setValueType(ValueType.TEXT); + CategoryOptionCombo defaultCategoryOptionCombo = createCategoryOptionCombo('D'); + defaultCategoryOptionCombo.setCategoryCombo(categoryService.getDefaultCategoryCombo()); + OrganisationUnit organisationUnitA = createOrganisationUnit('A'); + Period period = createPeriod(new Date(), new Date()); + period.setPeriodType(PeriodType.getPeriodType(PeriodTypeEnum.MONTHLY)); + manager.persist(dataElement); + manager.persist(organisationUnitA); + manager.persist(period); + manager.persist(defaultCategoryOptionCombo); + CategoryOption categoryOption = createCategoryOption('A'); + categoryOption.setCategoryOptionCombos(Sets.newHashSet(defaultCategoryOptionCombo)); + manager.persist(categoryOption); + defaultCategoryOptionCombo.getCategoryOptions().add(categoryOption); + return createDataValue( + dataElement, period, organisationUnitA, "test", defaultCategoryOptionCombo); + } +}