diff --git a/jmix-data/eclipselink/src/main/java/io/jmix/eclipselink/impl/dbms/JmixHSQLPlatform.java b/jmix-data/eclipselink/src/main/java/io/jmix/eclipselink/impl/dbms/JmixHSQLPlatform.java index fbc20a98bc..74f4791060 100644 --- a/jmix-data/eclipselink/src/main/java/io/jmix/eclipselink/impl/dbms/JmixHSQLPlatform.java +++ b/jmix-data/eclipselink/src/main/java/io/jmix/eclipselink/impl/dbms/JmixHSQLPlatform.java @@ -18,7 +18,9 @@ import org.eclipse.persistence.mappings.converters.Converter; import org.eclipse.persistence.platform.database.HSQLPlatform; +import org.eclipse.persistence.queries.Call; +import java.io.Writer; import java.sql.Types; public class JmixHSQLPlatform extends HSQLPlatform implements UuidMappingInfo { @@ -29,6 +31,11 @@ public boolean supportsNestingOuterJoins() { return true; } + @Override + public int appendParameterInternal(Call call, Writer writer, Object parameter) { + return super.appendParameterInternal(call, writer, convertToDataValueIfUUID(parameter)); + } + @Override public int getUuidSqlType() { return Types.VARCHAR; diff --git a/jmix-data/eclipselink/src/main/java/io/jmix/eclipselink/impl/dbms/JmixOraclePlatform.java b/jmix-data/eclipselink/src/main/java/io/jmix/eclipselink/impl/dbms/JmixOraclePlatform.java index e62aa41344..3f5579f7d3 100644 --- a/jmix-data/eclipselink/src/main/java/io/jmix/eclipselink/impl/dbms/JmixOraclePlatform.java +++ b/jmix-data/eclipselink/src/main/java/io/jmix/eclipselink/impl/dbms/JmixOraclePlatform.java @@ -17,9 +17,14 @@ package io.jmix.eclipselink.impl.dbms; import org.eclipse.persistence.exceptions.ConversionException; +import org.eclipse.persistence.internal.sessions.AbstractSession; import org.eclipse.persistence.mappings.converters.Converter; import org.eclipse.persistence.platform.database.Oracle10Platform; +import org.eclipse.persistence.queries.Call; +import java.io.Writer; +import java.sql.PreparedStatement; +import java.sql.SQLException; import java.sql.Types; import java.util.UUID; @@ -33,6 +38,16 @@ public Object convertObject(Object sourceObject, Class javaClass) throws Convers return super.convertObject(sourceObject, javaClass); } + @Override + public int appendParameterInternal(Call call, Writer writer, Object parameter) { + return super.appendParameterInternal(call, writer, convertToDataValueIfUUID(parameter)); + } + + @Override + public void setParameterValueInDatabaseCall(Object parameter, PreparedStatement statement, int index, AbstractSession session) throws SQLException { + super.setParameterValueInDatabaseCall(convertToDataValueIfUUID(parameter), statement, index, session); + } + @Override public int getUuidSqlType() { return Types.VARCHAR; diff --git a/jmix-data/eclipselink/src/main/java/io/jmix/eclipselink/impl/dbms/UuidMappingInfo.java b/jmix-data/eclipselink/src/main/java/io/jmix/eclipselink/impl/dbms/UuidMappingInfo.java index 68bb0aa0e0..f311ec8ab2 100644 --- a/jmix-data/eclipselink/src/main/java/io/jmix/eclipselink/impl/dbms/UuidMappingInfo.java +++ b/jmix-data/eclipselink/src/main/java/io/jmix/eclipselink/impl/dbms/UuidMappingInfo.java @@ -18,6 +18,8 @@ import org.eclipse.persistence.mappings.converters.Converter; +import java.util.UUID; + public interface UuidMappingInfo { int getUuidSqlType(); @@ -27,4 +29,22 @@ public interface UuidMappingInfo { String getUuidColumnDefinition(); Converter getUuidConverter(); + + /** + * Sometimes for some complex queries Eclipselink does not process collection parameter elements with converters. + * It only appends them to query using limited set of conversion checks instead. + * E.g. in org.eclipse.persistence.internal.databaseaccess.DatabasePlatform#setParameterValueInDatabaseCall(..) + * or in org.eclipse.persistence.internal.databaseaccess.DatabasePlatform#printValuelist(..) + * for case jmix-framework/jmix#1073 + *

+ * We have to convert UUID manually in such cases for several database types. + * + * @return converted to db type UUID parameter or the same parameter for other types + */ + default Object convertToDataValueIfUUID(Object parameter) { + if (parameter instanceof UUID) { + parameter = getUuidConverter().convertObjectValueToDataValue(parameter, null); + } + return parameter; + } } diff --git a/jmix-data/eclipselink/src/test/groovy/jpa_converter/JpaConverterTest.groovy b/jmix-data/eclipselink/src/test/groovy/jpa_converter/JpaConverterTest.groovy index d4c5e03953..6f94cf5026 100644 --- a/jmix-data/eclipselink/src/test/groovy/jpa_converter/JpaConverterTest.groovy +++ b/jmix-data/eclipselink/src/test/groovy/jpa_converter/JpaConverterTest.groovy @@ -18,11 +18,13 @@ package jpa_converter import io.jmix.core.DataManager import io.jmix.core.Id +import org.springframework.beans.factory.annotation.Autowired import test_support.DataSpec +import test_support.entity.TestAppEntity +import test_support.entity.TestAppEntityItem import test_support.entity.TestConverterEntity import test_support.entity.TestPhone -import org.springframework.beans.factory.annotation.Autowired import javax.sql.DataSource class JpaConverterTest extends DataSpec { @@ -55,4 +57,29 @@ class JpaConverterTest extends DataSpec { def dataType = resultSet.getInt('DATA_TYPE') dataType == java.sql.Types.VARCHAR } + + def "test UUID conversion for 'in' clause"() { + when: + def appEntity = dataManager.create(TestAppEntity) + appEntity.name = "test app entity 1" + + def appEntityItem = dataManager.create(TestAppEntityItem) + appEntityItem.appEntity = appEntity + + dataManager.save(appEntity, appEntityItem) + + List items = dataManager.load(TestAppEntityItem) + .query("select i from test_TestAppEntityItem i where ((i.appEntity in :appEntities) and (('1' = '1') or (i.name = '1')))") + .parameter("appEntities", List.of(appEntity)) + .list() + then: + noExceptionThrown() + items.size() == 1 + items.iterator().next() == appEntityItem + + cleanup: + if (appEntityItem != null) dataManager.remove(appEntityItem) + if (appEntity != null) dataManager.remove(appEntity) + + } }