Fix failures with inline value handling mode
This commit is contained in:
parent
c8a4546331
commit
be49444822
|
@ -29,7 +29,19 @@ public interface EntityIdentifierMapping extends ValueMapping, ModelPart {
|
|||
*/
|
||||
IdentifierValue getUnsavedStrategy();
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return the entity identifier value
|
||||
*
|
||||
* @deprecated Use {@link #getIdentifier(Object)}
|
||||
*/
|
||||
@Deprecated
|
||||
Object getIdentifier(Object entity, SharedSessionContractImplementor session);
|
||||
|
||||
Object getIdentifier(Object entity);
|
||||
|
||||
void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session);
|
||||
|
||||
Object instantiate();
|
||||
}
|
||||
|
|
|
@ -124,6 +124,14 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
|
|||
return propertyAccess.getGetter().get( entity );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getIdentifier(Object entity) {
|
||||
if ( entity instanceof HibernateProxy ) {
|
||||
return ( (HibernateProxy) entity ).getHibernateLazyInitializer().getIdentifier();
|
||||
}
|
||||
return propertyAccess.getGetter().get( entity );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session) {
|
||||
propertyAccess.getSetter().set( entity, id );
|
||||
|
|
|
@ -200,7 +200,7 @@ public class DiscriminatedAssociationAttributeMapping
|
|||
final Object discriminator = discriminatorMapping
|
||||
.getModelPart()
|
||||
.resolveDiscriminatorForEntityType( concreteMappingType );
|
||||
final Object identifier = identifierMapping.getIdentifier( value, session );
|
||||
final Object identifier = identifierMapping.getIdentifier( value );
|
||||
|
||||
return new Object[] {
|
||||
discriminatorMapping.getDiscriminatorPart().disassemble( discriminator, session ),
|
||||
|
@ -271,7 +271,7 @@ public class DiscriminatedAssociationAttributeMapping
|
|||
);
|
||||
|
||||
final EntityIdentifierMapping identifierMapping = concreteMappingType.getIdentifierMapping();
|
||||
final Object identifier = identifierMapping.getIdentifier( value, session );
|
||||
final Object identifier = identifierMapping.getIdentifier( value );
|
||||
final Object disassembledKey = discriminatorMapping.getKeyPart().disassemble( identifier, session );
|
||||
valuesConsumer.consume(
|
||||
offset + 1,
|
||||
|
@ -295,7 +295,7 @@ public class DiscriminatedAssociationAttributeMapping
|
|||
valueConsumer.consume( disassembledDiscriminator, discriminatorMapping.getDiscriminatorPart() );
|
||||
|
||||
final EntityIdentifierMapping identifierMapping = concreteMappingType.getIdentifierMapping();
|
||||
final Object identifier = identifierMapping.getIdentifier( domainValue, session );
|
||||
final Object identifier = identifierMapping.getIdentifier( domainValue );
|
||||
final Object disassembledKey = discriminatorMapping.getKeyPart().disassemble( identifier, session );
|
||||
valueConsumer.consume( disassembledKey, discriminatorMapping.getKeyPart() );
|
||||
}
|
||||
|
|
|
@ -589,10 +589,10 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
}
|
||||
// If the mapping type has an identifier type, that identifier is the key
|
||||
if ( modelPart instanceof SingleAttributeIdentifierMapping ) {
|
||||
return ( (SingleAttributeIdentifierMapping) modelPart ).getIdentifier( targetObject, session );
|
||||
return ( (SingleAttributeIdentifierMapping) modelPart ).getIdentifier( targetObject );
|
||||
}
|
||||
else if ( modelPart instanceof CompositeIdentifierMapping ) {
|
||||
return ( (CompositeIdentifierMapping) modelPart ).getIdentifier( targetObject, session );
|
||||
return ( (CompositeIdentifierMapping) modelPart ).getIdentifier( targetObject );
|
||||
}
|
||||
// Otherwise, this is a key based on the target object i.e. without id-class
|
||||
return targetObject;
|
||||
|
|
|
@ -85,6 +85,14 @@ public class EmbeddedIdentifierMappingImpl
|
|||
return propertyAccess.getGetter().get( entity );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getIdentifier(Object entity) {
|
||||
if ( entity instanceof HibernateProxy ) {
|
||||
return ( (HibernateProxy) entity ).getHibernateLazyInitializer().getIdentifier();
|
||||
}
|
||||
return propertyAccess.getGetter().get( entity );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdentifier(Object entity, Object id, SharedSessionContractImplementor session) {
|
||||
propertyAccess.getSetter().set( entity, id );
|
||||
|
|
|
@ -173,7 +173,7 @@ public class IdClassEmbeddable extends AbstractEmbeddableMapping implements Iden
|
|||
toOneAttributeMapping.getSideNature().inverse()
|
||||
);
|
||||
if ( targetPart instanceof EntityIdentifierMapping ) {
|
||||
propertyValues[i] = ( (EntityIdentifierMapping) targetPart ).getIdentifier( o, session );
|
||||
propertyValues[i] = ( (EntityIdentifierMapping) targetPart ).getIdentifier( o );
|
||||
}
|
||||
else {
|
||||
propertyValues[i] = o;
|
||||
|
|
|
@ -202,6 +202,11 @@ public class NonAggregatedIdentifierMappingImpl extends AbstractCompositeIdentif
|
|||
|
||||
@Override
|
||||
public Object getIdentifier(Object entity, SharedSessionContractImplementor session) {
|
||||
return getIdentifier( entity );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getIdentifier(Object entity) {
|
||||
if ( hasContainingClass() ) {
|
||||
final Object id = identifierValueMapper.getRepresentationStrategy().getInstantiator().instantiate(
|
||||
null,
|
||||
|
@ -230,7 +235,7 @@ public class NonAggregatedIdentifierMappingImpl extends AbstractCompositeIdentif
|
|||
toOneAttributeMapping.getSideNature().inverse()
|
||||
);
|
||||
if ( targetPart instanceof EntityIdentifierMapping ) {
|
||||
propertyValues[i] = ( (EntityIdentifierMapping) targetPart ).getIdentifier( o, session );
|
||||
propertyValues[i] = ( (EntityIdentifierMapping) targetPart ).getIdentifier( o );
|
||||
}
|
||||
else {
|
||||
propertyValues[i] = o;
|
||||
|
|
|
@ -5046,7 +5046,7 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
@Override
|
||||
public Object getIdentifier(Object entity, SharedSessionContractImplementor session) {
|
||||
return identifierMapping.getIdentifier( entity, session );
|
||||
return identifierMapping.getIdentifier( entity );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -6508,7 +6508,7 @@ public abstract class AbstractEntityPersister
|
|||
return null;
|
||||
}
|
||||
final EntityIdentifierMapping identifierMapping = getIdentifierMapping();
|
||||
final Object identifier = identifierMapping.getIdentifier( value, session );
|
||||
final Object identifier = identifierMapping.getIdentifier( value );
|
||||
return identifierMapping.disassemble( identifier, session );
|
||||
}
|
||||
|
||||
|
@ -6541,7 +6541,7 @@ public abstract class AbstractEntityPersister
|
|||
identifier = null;
|
||||
}
|
||||
else {
|
||||
identifier = identifierMapping.disassemble( identifierMapping.getIdentifier( value, session ), session );
|
||||
identifier = identifierMapping.disassemble( identifierMapping.getIdentifier( value ), session );
|
||||
}
|
||||
return identifierMapping.forEachDisassembledJdbcValue(
|
||||
identifier,
|
||||
|
|
|
@ -365,7 +365,7 @@ public class SqmUtil {
|
|||
final EntityIdentifierMapping identifierMapping = (EntityIdentifierMapping) parameterType;
|
||||
final EntityMappingType entityMapping = identifierMapping.findContainingEntityMapping();
|
||||
if ( entityMapping.getRepresentationStrategy().getInstantiator().isInstance( bindValue, session.getFactory() ) ) {
|
||||
bindValue = identifierMapping.getIdentifier( bindValue, session );
|
||||
bindValue = identifierMapping.getIdentifier( bindValue );
|
||||
}
|
||||
}
|
||||
else if ( parameterType instanceof EntityMappingType ) {
|
||||
|
@ -373,7 +373,7 @@ public class SqmUtil {
|
|||
final EntityMappingType entityMapping = identifierMapping.findContainingEntityMapping();
|
||||
parameterType = identifierMapping;
|
||||
if ( entityMapping.getRepresentationStrategy().getInstantiator().isInstance( bindValue, session.getFactory() ) ) {
|
||||
bindValue = identifierMapping.getIdentifier( bindValue, session );
|
||||
bindValue = identifierMapping.getIdentifier( bindValue );
|
||||
}
|
||||
}
|
||||
else if ( parameterType instanceof ToOneAttributeMapping ) {
|
||||
|
|
|
@ -87,8 +87,10 @@ import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
|||
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.internal.BasicSqmPathSource;
|
||||
import org.hibernate.metamodel.model.domain.internal.CompositeSqmPathSource;
|
||||
import org.hibernate.metamodel.model.domain.internal.DiscriminatorSqmPath;
|
||||
import org.hibernate.metamodel.model.domain.internal.EntityTypeImpl;
|
||||
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.Joinable;
|
||||
|
@ -3934,31 +3936,12 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
|
||||
if ( inferableExpressible instanceof ConvertibleModelPart ) {
|
||||
final ConvertibleModelPart convertibleModelPart = (ConvertibleModelPart) inferableExpressible;
|
||||
final BasicValueConverter valueConverter = convertibleModelPart.getValueConverter();
|
||||
|
||||
if ( valueConverter != null ) {
|
||||
final Object literalValue = literal.getLiteralValue();
|
||||
final Object sqlLiteralValue;
|
||||
|
||||
if ( valueConverter.getDomainJavaType().getJavaTypeClass().isInstance( literalValue ) ) {
|
||||
sqlLiteralValue = valueConverter.toRelationalValue( literalValue );
|
||||
}
|
||||
else {
|
||||
if ( !valueConverter.getRelationalJavaType().getJavaTypeClass().isInstance( literalValue ) ) {
|
||||
throw new SqlTreeCreationException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"QueryLiteral type [`%s`] did not match domain Java-type [`%s`] nor JDBC Java-type [`%s`]",
|
||||
literalValue.getClass(),
|
||||
valueConverter.getDomainJavaType().getJavaTypeClass().getName(),
|
||||
valueConverter.getRelationalJavaType().getJavaTypeClass().getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
sqlLiteralValue = literalValue;
|
||||
}
|
||||
|
||||
return new QueryLiteral<>( sqlLiteralValue, convertibleModelPart );
|
||||
if ( convertibleModelPart.getValueConverter() != null ) {
|
||||
return new QueryLiteral<>(
|
||||
literal.getLiteralValue(),
|
||||
convertibleModelPart
|
||||
);
|
||||
}
|
||||
}
|
||||
// Special case for when we create an entity literal through the JPA CriteriaBuilder.literal API
|
||||
|
@ -3998,6 +3981,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
return new EntityTypeLiteral( mappingDescriptor );
|
||||
}
|
||||
|
||||
|
||||
final MappingModelExpressible<?> expressible;
|
||||
final MappingModelExpressible<?> localExpressible = SqmMappingModelHelper.resolveMappingModelExpressible(
|
||||
literal,
|
||||
|
@ -4021,6 +4005,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
}
|
||||
}
|
||||
|
||||
if ( expressible instanceof EntityIdentifierMapping && literal.getNodeType() instanceof EntityTypeImpl ) {
|
||||
return new QueryLiteral<>(
|
||||
( (EntityIdentifierMapping) expressible ).getIdentifier( literal.getLiteralValue() ),
|
||||
(BasicValuedMapping) expressible
|
||||
);
|
||||
}
|
||||
|
||||
if ( expressible instanceof BasicValuedMapping ) {
|
||||
return new QueryLiteral<>(
|
||||
literal.getLiteralValue(),
|
||||
|
@ -4028,7 +4019,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
);
|
||||
}
|
||||
// Handling other values might seem unnecessary, but with JPA Criteria it is totally possible to have such literals
|
||||
else if ( expressible instanceof EmbeddableValuedModelPart ) {
|
||||
if ( expressible instanceof EmbeddableValuedModelPart ) {
|
||||
final EmbeddableValuedModelPart embeddableValuedModelPart = (EmbeddableValuedModelPart) expressible;
|
||||
final List<Expression> list = new ArrayList<>( embeddableValuedModelPart.getJdbcTypeCount() );
|
||||
embeddableValuedModelPart.forEachJdbcValue(
|
||||
|
@ -4042,46 +4033,41 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
}
|
||||
else if ( expressible instanceof EntityValuedModelPart ) {
|
||||
final EntityValuedModelPart entityValuedModelPart = (EntityValuedModelPart) expressible;
|
||||
final Object associationKey;
|
||||
final ModelPart associationKeyPart;
|
||||
if ( entityValuedModelPart instanceof Association ) {
|
||||
final Association association = (Association) entityValuedModelPart;
|
||||
final ForeignKeyDescriptor foreignKeyDescriptor = association.getForeignKeyDescriptor();
|
||||
associationKey = foreignKeyDescriptor.getAssociationKeyFromSide(
|
||||
literal.getLiteralValue(),
|
||||
association.getSideNature(),
|
||||
null
|
||||
);
|
||||
associationKeyPart = foreignKeyDescriptor.getPart( association.getSideNature() );
|
||||
}
|
||||
else {
|
||||
final EntityIdentifierMapping identifierMapping = entityValuedModelPart.getEntityMappingType()
|
||||
.getIdentifierMapping();
|
||||
associationKeyPart = identifierMapping;
|
||||
associationKey = identifierMapping.getIdentifier(
|
||||
literal.getLiteralValue(),
|
||||
null
|
||||
);
|
||||
}
|
||||
if ( associationKeyPart instanceof BasicValuedMapping ) {
|
||||
final EntityIdentifierMapping identifierMapping = entityValuedModelPart.getEntityMappingType()
|
||||
.getIdentifierMapping();
|
||||
final Object associationKey = identifierMapping.getIdentifier( literal.getLiteralValue() );
|
||||
if ( identifierMapping instanceof BasicValuedMapping ) {
|
||||
return new QueryLiteral<>(
|
||||
associationKey,
|
||||
(BasicValuedMapping) associationKeyPart
|
||||
(BasicValuedMapping) identifierMapping
|
||||
);
|
||||
}
|
||||
else {
|
||||
final List<Expression> list = new ArrayList<>( associationKeyPart.getJdbcTypeCount() );
|
||||
associationKeyPart.forEachJdbcValue(
|
||||
final List<Expression> list = new ArrayList<>( identifierMapping.getJdbcTypeCount() );
|
||||
identifierMapping.forEachJdbcValue(
|
||||
associationKey,
|
||||
null,
|
||||
(selectionIndex, value, jdbcMapping)
|
||||
-> list.add( new QueryLiteral<>( value, (BasicValuedMapping) jdbcMapping ) ),
|
||||
null
|
||||
);
|
||||
return new SqlTuple( list, associationKeyPart );
|
||||
return new SqlTuple( list, identifierMapping );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( literal instanceof SqmLiteral ) {
|
||||
return new QueryLiteral<>(
|
||||
literal.getLiteralValue(),
|
||||
creationContext.getSessionFactory()
|
||||
.getTypeConfiguration()
|
||||
.getBasicTypeRegistry()
|
||||
.getRegisteredType(
|
||||
( (BasicSqmPathSource) literal.getNodeType() ).getSqmPathType()
|
||||
.getJavaType()
|
||||
.getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
throw new NotYetImplementedFor6Exception(
|
||||
expressible == null ? literal.getLiteralValue().getClass() : expressible.getClass()
|
||||
);
|
||||
|
|
|
@ -8,12 +8,15 @@ package org.hibernate.sql.ast.tree.expression;
|
|||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.ConvertibleModelPart;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
||||
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
||||
import org.hibernate.sql.ast.SqlAstWalker;
|
||||
import org.hibernate.sql.ast.SqlTreeCreationException;
|
||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
|
@ -35,8 +38,43 @@ public class QueryLiteral<T> implements Literal, DomainResultProducer<T> {
|
|||
private final BasicValuedMapping type;
|
||||
|
||||
public QueryLiteral(T value, BasicValuedMapping type) {
|
||||
this.value = value;
|
||||
this.type = type;
|
||||
if ( type instanceof ConvertibleModelPart ) {
|
||||
final ConvertibleModelPart convertibleModelPart = (ConvertibleModelPart) type;
|
||||
final BasicValueConverter valueConverter = convertibleModelPart.getValueConverter();
|
||||
|
||||
if ( valueConverter != null ) {
|
||||
final Object literalValue = value;
|
||||
final Object sqlLiteralValue;
|
||||
|
||||
if ( valueConverter.getDomainJavaType().getJavaTypeClass().isInstance( literalValue ) ) {
|
||||
sqlLiteralValue = valueConverter.toRelationalValue( literalValue );
|
||||
}
|
||||
else {
|
||||
if ( !valueConverter.getRelationalJavaType().getJavaTypeClass().isInstance( literalValue ) ) {
|
||||
throw new SqlTreeCreationException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"QueryLiteral type [`%s`] did not match domain Java-type [`%s`] nor JDBC Java-type [`%s`]",
|
||||
literalValue.getClass(),
|
||||
valueConverter.getDomainJavaType().getJavaTypeClass().getName(),
|
||||
valueConverter.getRelationalJavaType().getJavaTypeClass().getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
sqlLiteralValue = literalValue;
|
||||
}
|
||||
this.value = (T) sqlLiteralValue;
|
||||
this.type = convertibleModelPart;
|
||||
}
|
||||
else {
|
||||
this.value = value;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.value = value;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
|
@ -196,7 +197,15 @@ public final class DateTimeUtils {
|
|||
}
|
||||
|
||||
public static void appendAsTimestampWithMicros(SqlAppender appender, Date date, TimeZone jdbcTimeZone) {
|
||||
final SimpleDateFormat simpleDateFormat = TIMESTAMP_WITH_MICROS_FORMAT.get();
|
||||
final SimpleDateFormat simpleDateFormat;
|
||||
if ( date instanceof Timestamp ) {
|
||||
// java.sql.Timestamp supports micro sec
|
||||
simpleDateFormat = TIMESTAMP_WITH_MICROS_FORMAT.get();
|
||||
}
|
||||
else {
|
||||
// java.util.Date supports only milli sec
|
||||
simpleDateFormat = TIMESTAMP_WITH_MILLIS_FORMAT.get();
|
||||
}
|
||||
final TimeZone originalTimeZone = simpleDateFormat.getTimeZone();
|
||||
try {
|
||||
simpleDateFormat.setTimeZone( jdbcTimeZone );
|
||||
|
@ -231,7 +240,8 @@ public final class DateTimeUtils {
|
|||
}
|
||||
|
||||
public static void appendAsTimestampWithMicros(SqlAppender appender, Calendar calendar, TimeZone jdbcTimeZone) {
|
||||
final SimpleDateFormat simpleDateFormat = TIMESTAMP_WITH_MICROS_FORMAT.get();
|
||||
// it is possible to use micro sec resolution with java.util.Date
|
||||
final SimpleDateFormat simpleDateFormat = TIMESTAMP_WITH_MILLIS_FORMAT.get();
|
||||
final TimeZone originalTimeZone = simpleDateFormat.getTimeZone();
|
||||
try {
|
||||
simpleDateFormat.setTimeZone( jdbcTimeZone );
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.type.descriptor.jdbc.spi;
|
||||
|
||||
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
||||
|
@ -29,6 +28,18 @@ public abstract class BasicJdbcLiteralFormatter extends AbstractJdbcLiteralForma
|
|||
return (X) value;
|
||||
}
|
||||
|
||||
if ( !getJavaType().isInstance( value ) ) {
|
||||
final Object coerce = getJavaType().coerce( value, wrapperOptions.getSession() );
|
||||
if ( unwrapType.isInstance( coerce ) ) {
|
||||
return (X) coerce;
|
||||
}
|
||||
return (X) getJavaType().unwrap(
|
||||
coerce,
|
||||
unwrapType,
|
||||
wrapperOptions
|
||||
);
|
||||
}
|
||||
|
||||
return (X) getJavaType().unwrap( value, unwrapType, wrapperOptions );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.jpa.compliance;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -22,7 +31,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@Jpa(
|
||||
annotatedClasses = ModulusTest.Person.class
|
||||
annotatedClasses = ModulusTest.Person.class,
|
||||
properties = @Setting( name = AvailableSettings.JPA_QUERY_COMPLIANCE, value = "true")
|
||||
)
|
||||
public class ModulusTest {
|
||||
|
||||
|
|
|
@ -10,7 +10,21 @@ import java.math.BigDecimal;
|
|||
import java.math.BigInteger;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
import org.hibernate.dialect.DB2Dialect;
|
||||
import org.hibernate.dialect.DerbyDialect;
|
||||
import org.hibernate.orm.test.jpa.metamodel.AbstractMetamodelSpecificTest;
|
||||
import org.hibernate.orm.test.jpa.metamodel.Phone;
|
||||
import org.hibernate.orm.test.jpa.metamodel.Product;
|
||||
import org.hibernate.orm.test.jpa.metamodel.Product_;
|
||||
import org.hibernate.query.Query;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.TypedQuery;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
|
@ -18,21 +32,7 @@ import jakarta.persistence.criteria.ParameterExpression;
|
|||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
import org.hibernate.dialect.DB2Dialect;
|
||||
import org.hibernate.dialect.DerbyDialect;
|
||||
import org.hibernate.query.Query;
|
||||
import org.hibernate.orm.test.jpa.metamodel.AbstractMetamodelSpecificTest;
|
||||
import org.hibernate.orm.test.jpa.metamodel.Phone;
|
||||
import org.hibernate.orm.test.jpa.metamodel.Product;
|
||||
import org.hibernate.orm.test.jpa.metamodel.Product_;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
|
@ -47,175 +47,187 @@ public class ExpressionsTest extends AbstractMetamodelSpecificTest {
|
|||
public void prepareTestData() {
|
||||
builder = entityManagerFactory().getCriteriaBuilder();
|
||||
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
Product product = new Product();
|
||||
product.setId( "product1" );
|
||||
product.setPrice( 1.23d );
|
||||
product.setQuantity( 2 );
|
||||
product.setPartNumber( ((long)Integer.MAX_VALUE) + 1 );
|
||||
product.setRating( 1.999f );
|
||||
product.setSomeBigInteger( BigInteger.valueOf( 987654321 ) );
|
||||
product.setSomeBigDecimal( BigDecimal.valueOf( 987654.32 ) );
|
||||
em.persist( product );
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
doInJPA(
|
||||
this::entityManagerFactory,
|
||||
entityManager -> {
|
||||
Product product = new Product();
|
||||
product.setId( "product1" );
|
||||
product.setPrice( 1.23d );
|
||||
product.setQuantity( 2 );
|
||||
product.setPartNumber( ( (long) Integer.MAX_VALUE ) + 1 );
|
||||
product.setRating( 1.999f );
|
||||
product.setSomeBigInteger( BigInteger.valueOf( 987654321 ) );
|
||||
product.setSomeBigDecimal( BigDecimal.valueOf( 987654.32 ) );
|
||||
entityManager.persist( product );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void cleanupTestData() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
em.remove( em.find( Product.class, "product1" ) );
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
doInJPA(
|
||||
this::entityManagerFactory,
|
||||
entityManager -> {
|
||||
entityManager.createQuery( "delete from Product" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyConjunction() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.where( builder.and() );
|
||||
List<Product> result = em.createQuery( criteria ).getResultList();
|
||||
assertEquals( 1, result.size() );
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
doInJPA(
|
||||
this::entityManagerFactory,
|
||||
entityManager -> {
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.where( builder.and() );
|
||||
List<Product> result = entityManager.createQuery( criteria ).getResultList();
|
||||
assertEquals( 1, result.size() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-6876" )
|
||||
@TestForIssue(jiraKey = "HHH-6876")
|
||||
public void testEmptyInList() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
Root<Product> from = criteria.from( Product.class );
|
||||
criteria.where( from.get( Product_.partNumber ).in() ); // empty IN list
|
||||
List<Product> result = em.createQuery( criteria ).getResultList();
|
||||
assertEquals( 0, result.size() );
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
doInJPA(
|
||||
this::entityManagerFactory,
|
||||
entityManager -> {
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
Root<Product> from = criteria.from( Product.class );
|
||||
criteria.where( from.get( Product_.partNumber ).in() ); // empty IN list
|
||||
List<Product> result = entityManager.createQuery( criteria ).getResultList();
|
||||
assertEquals( 0, result.size() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyConjunctionIsTrue() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.where( builder.isTrue( builder.and() ) );
|
||||
List<Product> result = em.createQuery( criteria ).getResultList();
|
||||
assertEquals( 1, result.size() );
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
doInJPA(
|
||||
this::entityManagerFactory,
|
||||
entityManager -> {
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.where( builder.isTrue( builder.and() ) );
|
||||
List<Product> result = entityManager.createQuery( criteria ).getResultList();
|
||||
assertEquals( 1, result.size() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyConjunctionIsFalse() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.where( builder.isFalse( builder.and() ) );
|
||||
List<Product> result = em.createQuery( criteria ).getResultList();
|
||||
assertEquals( 0, result.size() );
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
doInJPA(
|
||||
this::entityManagerFactory,
|
||||
entityManager -> {
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.where( builder.isFalse( builder.and() ) );
|
||||
List<Product> result = entityManager.createQuery( criteria ).getResultList();
|
||||
assertEquals( 0, result.size() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyDisjunction() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.where( builder.disjunction() );
|
||||
List<Product> result = em.createQuery( criteria ).getResultList();
|
||||
assertEquals( 0, result.size() );
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
doInJPA(
|
||||
this::entityManagerFactory,
|
||||
entityManager -> {
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.where( builder.disjunction() );
|
||||
List<Product> result = entityManager.createQuery( criteria ).getResultList();
|
||||
assertEquals( 0, result.size() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyDisjunctionIsTrue() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.where( builder.isTrue( builder.disjunction() ) );
|
||||
List<Product> result = em.createQuery( criteria ).getResultList();
|
||||
assertEquals( 0, result.size() );
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
doInJPA(
|
||||
this::entityManagerFactory,
|
||||
entityManager -> {
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.where( builder.isTrue( builder.disjunction() ) );
|
||||
List<Product> result = entityManager.createQuery( criteria ).getResultList();
|
||||
assertEquals( 0, result.size() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyDisjunctionIsFalse() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.where( builder.isFalse( builder.disjunction() ) );
|
||||
List<Product> result = em.createQuery( criteria ).getResultList();
|
||||
assertEquals( 1, result.size() );
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
doInJPA(
|
||||
this::entityManagerFactory,
|
||||
entityManager -> {
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.where( builder.isFalse( builder.disjunction() ) );
|
||||
List<Product> result = entityManager.createQuery( criteria ).getResultList();
|
||||
assertEquals( 1, result.size() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDiff() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
CriteriaQuery<Integer> criteria = builder.createQuery( Integer.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.select( builder.diff( builder.literal( 5 ), builder.literal( 2 ) ) );
|
||||
Integer result = em.createQuery( criteria ).getSingleResult();
|
||||
assertEquals( Integer.valueOf( 3 ), result );
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
doInJPA(
|
||||
this::entityManagerFactory,
|
||||
entityManager -> {
|
||||
CriteriaQuery<Integer> criteria = builder.createQuery( Integer.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.select( builder.diff( builder.literal( 5 ), builder.literal( 2 ) ) );
|
||||
Integer result = entityManager.createQuery( criteria ).getSingleResult();
|
||||
assertEquals( Integer.valueOf( 3 ), result );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDiffWithQuotient() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
CriteriaQuery<Number> criteria = builder.createQuery( Number.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.select(
|
||||
builder.quot(
|
||||
builder.diff(
|
||||
builder.literal( BigDecimal.valueOf( 2.0 ) ),
|
||||
builder.literal( BigDecimal.valueOf( 1.0 ) )
|
||||
),
|
||||
BigDecimal.valueOf( 2.0 )
|
||||
)
|
||||
doInJPA(
|
||||
this::entityManagerFactory,
|
||||
entityManager -> {
|
||||
CriteriaQuery<Number> criteria = builder.createQuery( Number.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.select(
|
||||
builder.quot(
|
||||
builder.diff(
|
||||
builder.literal( BigDecimal.valueOf( 2.0 ) ),
|
||||
builder.literal( BigDecimal.valueOf( 1.0 ) )
|
||||
),
|
||||
BigDecimal.valueOf( 2.0 )
|
||||
)
|
||||
);
|
||||
Number result = entityManager.createQuery( criteria ).getSingleResult();
|
||||
assertEquals( 0.5d, result.doubleValue(), 0.1d );
|
||||
}
|
||||
);
|
||||
Number result = em.createQuery( criteria ).getSingleResult();
|
||||
assertEquals(0.5d, result.doubleValue(), 0.1d);
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSumWithQuotient() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
CriteriaQuery<Number> criteria = builder.createQuery( Number.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.select(
|
||||
builder.quot(
|
||||
builder.sum(
|
||||
builder.literal( BigDecimal.valueOf( 0.0 ) ),
|
||||
builder.literal( BigDecimal.valueOf( 1.0 ) )
|
||||
),
|
||||
BigDecimal.valueOf( 2.0 )
|
||||
)
|
||||
doInJPA(
|
||||
this::entityManagerFactory,
|
||||
entityManager -> {
|
||||
CriteriaQuery<Number> criteria = builder.createQuery( Number.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.select(
|
||||
builder.quot(
|
||||
builder.sum(
|
||||
builder.literal( BigDecimal.valueOf( 0.0 ) ),
|
||||
builder.literal( BigDecimal.valueOf( 1.0 ) )
|
||||
),
|
||||
BigDecimal.valueOf( 2.0 )
|
||||
)
|
||||
);
|
||||
Number result = entityManager.createQuery( criteria ).getSingleResult();
|
||||
assertEquals( 0.5d, result.doubleValue(), 0.1d );
|
||||
}
|
||||
);
|
||||
Number result = em.createQuery( criteria ).getSingleResult();
|
||||
assertEquals(0.5d, result.doubleValue(), 0.1d);
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -225,55 +237,56 @@ public class ExpressionsTest extends AbstractMetamodelSpecificTest {
|
|||
"that is always rendered as literal. Since numeric literal + parameter arithmetic is rare, we skip this for now.")
|
||||
@SkipForDialect(dialectClass = DB2Dialect.class, reason = "Same reason as for Derby")
|
||||
public void testQuotientAndMultiply() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
CriteriaQuery<Number> criteria = builder.createQuery( Number.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.select(
|
||||
builder.quot(
|
||||
builder.prod(
|
||||
builder.literal( BigDecimal.valueOf( 10.0 ) ),
|
||||
builder.literal( BigDecimal.valueOf( 5.0 ) )
|
||||
),
|
||||
BigDecimal.valueOf( 2.0 )
|
||||
)
|
||||
);
|
||||
Number result = em.createQuery( criteria ).getSingleResult();
|
||||
assertEquals(25.0d, result.doubleValue(), 0.1d);
|
||||
doInJPA(
|
||||
this::entityManagerFactory,
|
||||
entityManager -> {
|
||||
CriteriaQuery<Number> criteria = builder.createQuery( Number.class );
|
||||
criteria.from( Product.class );
|
||||
criteria.select(
|
||||
builder.quot(
|
||||
builder.prod(
|
||||
builder.literal( BigDecimal.valueOf( 10.0 ) ),
|
||||
builder.literal( BigDecimal.valueOf( 5.0 ) )
|
||||
),
|
||||
BigDecimal.valueOf( 2.0 )
|
||||
)
|
||||
);
|
||||
Number result = entityManager.createQuery( criteria ).getSingleResult();
|
||||
assertEquals( 25.0d, result.doubleValue(), 0.1d );
|
||||
|
||||
criteria.select(
|
||||
builder.prod(
|
||||
builder.quot(
|
||||
builder.literal( BigDecimal.valueOf( 10.0 ) ),
|
||||
builder.literal( BigDecimal.valueOf( 5.0 ) )
|
||||
),
|
||||
BigDecimal.valueOf( 2.0 )
|
||||
)
|
||||
criteria.select(
|
||||
builder.prod(
|
||||
builder.quot(
|
||||
builder.literal( BigDecimal.valueOf( 10.0 ) ),
|
||||
builder.literal( BigDecimal.valueOf( 5.0 ) )
|
||||
),
|
||||
BigDecimal.valueOf( 2.0 )
|
||||
)
|
||||
);
|
||||
result = entityManager.createQuery( criteria ).getSingleResult();
|
||||
assertEquals( 4.0d, result.doubleValue(), 0.1d );
|
||||
}
|
||||
);
|
||||
result = em.createQuery( criteria ).getSingleResult();
|
||||
assertEquals(4.0d, result.doubleValue(), 0.1d);
|
||||
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParameterReuse() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
CriteriaQuery<Product> criteria = em.getCriteriaBuilder().createQuery( Product.class );
|
||||
Root<Product> from = criteria.from( Product.class );
|
||||
ParameterExpression<String> param = em.getCriteriaBuilder().parameter( String.class );
|
||||
Predicate predicate = em.getCriteriaBuilder().equal( from.get( Product_.id ), param );
|
||||
Predicate predicate2 = em.getCriteriaBuilder().equal( from.get( Product_.name ), param );
|
||||
criteria.where( em.getCriteriaBuilder().or( predicate, predicate2 ) );
|
||||
assertEquals( 1, criteria.getParameters().size() );
|
||||
TypedQuery<Product> query = em.createQuery( criteria );
|
||||
int hqlParamCount = countGeneratedParameters( query.unwrap( Query.class ) );
|
||||
assertEquals( 1, hqlParamCount );
|
||||
query.setParameter( param, "abc" ).getResultList();
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
doInJPA(
|
||||
this::entityManagerFactory,
|
||||
entityManager -> {
|
||||
CriteriaQuery<Product> criteria = entityManager.getCriteriaBuilder().createQuery( Product.class );
|
||||
Root<Product> from = criteria.from( Product.class );
|
||||
ParameterExpression<String> param = entityManager.getCriteriaBuilder().parameter( String.class );
|
||||
Predicate predicate = entityManager.getCriteriaBuilder().equal( from.get( Product_.id ), param );
|
||||
Predicate predicate2 = entityManager.getCriteriaBuilder().equal( from.get( Product_.name ), param );
|
||||
criteria.where( entityManager.getCriteriaBuilder().or( predicate, predicate2 ) );
|
||||
assertEquals( 1, criteria.getParameters().size() );
|
||||
TypedQuery<Product> query = entityManager.createQuery( criteria );
|
||||
int hqlParamCount = countGeneratedParameters( query.unwrap( Query.class ) );
|
||||
assertEquals( 1, hqlParamCount );
|
||||
query.setParameter( param, "abc" ).getResultList();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private int countGeneratedParameters(Query<?> query) {
|
||||
|
@ -282,55 +295,60 @@ public class ExpressionsTest extends AbstractMetamodelSpecificTest {
|
|||
|
||||
@Test
|
||||
public void testInExplicitTupleList() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
Root<Product> from = criteria.from( Product.class );
|
||||
criteria.where( from.get( Product_.partNumber ).in( Collections.singletonList( ((long)Integer.MAX_VALUE) + 1 ) ) );
|
||||
List<Product> result = em.createQuery( criteria ).getResultList();
|
||||
assertEquals( 1, result.size() );
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
doInJPA(
|
||||
this::entityManagerFactory,
|
||||
entityManager -> {
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
Root<Product> from = criteria.from( Product.class );
|
||||
criteria.where( from.get( Product_.partNumber )
|
||||
.in( Collections.singletonList( ( (long) Integer.MAX_VALUE ) + 1 ) ) );
|
||||
List<Product> result = entityManager.createQuery( criteria ).getResultList();
|
||||
assertEquals( 1, result.size() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInExplicitTupleListVarargs() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
Root<Product> from = criteria.from( Product.class );
|
||||
criteria.where( from.get( Product_.partNumber ).in( ((long)Integer.MAX_VALUE) + 1 ) );
|
||||
List<Product> result = em.createQuery( criteria ).getResultList();
|
||||
assertEquals( 1, result.size() );
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
doInJPA(
|
||||
this::entityManagerFactory,
|
||||
entityManager -> {
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
Root<Product> from = criteria.from( Product.class );
|
||||
criteria.where( from.get( Product_.partNumber ).in( ( (long) Integer.MAX_VALUE ) + 1 ) );
|
||||
List<Product> result = entityManager.createQuery( criteria ).getResultList();
|
||||
assertEquals( 1, result.size() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInExpressionVarargs() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
Root<Product> from = criteria.from( Product.class );
|
||||
criteria.where( from.get( Product_.partNumber ).in( from.get( Product_.partNumber ) ) );
|
||||
List<Product> result = em.createQuery( criteria ).getResultList();
|
||||
assertEquals( 1, result.size() );
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
doInJPA(
|
||||
this::entityManagerFactory,
|
||||
entityManager -> {
|
||||
CriteriaQuery<Product> criteria = builder.createQuery( Product.class );
|
||||
Root<Product> from = criteria.from( Product.class );
|
||||
criteria.where( from.get( Product_.partNumber ).in( from.get( Product_.partNumber ) ) );
|
||||
List<Product> result = entityManager.createQuery( criteria ).getResultList();
|
||||
assertEquals( 1, result.size() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJoinedElementCollectionValuesInTupleList() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
CriteriaQuery<Phone> criteria = builder.createQuery( Phone.class );
|
||||
Root<Phone> from = criteria.from( Phone.class );
|
||||
criteria.where(
|
||||
from.join( "types" )
|
||||
.in( Collections.singletonList( Phone.Type.WORK ) )
|
||||
doInJPA(
|
||||
this::entityManagerFactory,
|
||||
entityManager -> {
|
||||
CriteriaQuery<Phone> criteria = builder.createQuery( Phone.class );
|
||||
Root<Phone> from = criteria.from( Phone.class );
|
||||
criteria.where(
|
||||
from.join( "types" )
|
||||
.in( Collections.singletonList( Phone.Type.WORK ) )
|
||||
);
|
||||
entityManager.createQuery( criteria ).getResultList();
|
||||
}
|
||||
);
|
||||
em.createQuery( criteria ).getResultList();
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.jpa.criteria.valuehandlingmode.inline;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.ElementCollection;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.persistence.Embedded;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.MappedSuperclass;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
@Jpa(
|
||||
annotatedClasses = {
|
||||
ComponentInWhereClauseTest.Employee.class,
|
||||
ComponentInWhereClauseTest.Project.class,
|
||||
ComponentInWhereClauseTest.Person.class
|
||||
}
|
||||
, properties = @Setting(name = AvailableSettings.CRITERIA_VALUE_HANDLING_MODE, value = "inline")
|
||||
)
|
||||
public class ComponentInWhereClauseTest {
|
||||
private Projects projects;
|
||||
|
||||
@BeforeAll
|
||||
public void setUp(EntityManagerFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
entityManager -> {
|
||||
projects = new Projects();
|
||||
projects.addPreviousProject( new Project( "First" ) );
|
||||
projects.addPreviousProject( new Project( "Second" ) );
|
||||
projects.setCurrentProject( new Project( "Third" ) );
|
||||
|
||||
ContactDetail contactDetail = new ContactDetail();
|
||||
contactDetail.setEmail( "abc@mail.org" );
|
||||
contactDetail.addPhone( new Phone( "+4411111111" ) );
|
||||
|
||||
final Employee employee = new Employee();
|
||||
employee.setProjects( projects );
|
||||
employee.setContactDetail( contactDetail );
|
||||
entityManager.persist( employee );
|
||||
|
||||
final Person person = new Person();
|
||||
person.setInformation( new Information() );
|
||||
ContactDetail infoContactDetail = new ContactDetail();
|
||||
infoContactDetail.setEmail( "xyz@mail.org" );
|
||||
infoContactDetail.addPhone( new Phone( "999-999-9999" ) );
|
||||
person.getInformation().setInfoContactDetail( infoContactDetail );
|
||||
entityManager.persist( person );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInExpressionForTheManyToOnePropertyOfAComponent(EntityManagerFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
entityManager -> {
|
||||
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<Employee> query = builder.createQuery( Employee.class );
|
||||
Root<Employee> root = query.from( Employee.class );
|
||||
|
||||
query.where( root.get( "projects" )
|
||||
.get( "currentProject" )
|
||||
.in( projects.getCurrentProject() ) );
|
||||
|
||||
final List<Employee> results = entityManager.createQuery( query ).getResultList();
|
||||
assertThat( results.size(), is( 1 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@MappedSuperclass
|
||||
public static abstract class AbstractEntity {
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
protected Long id;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Employee")
|
||||
@Table(name = "EMPLOYEE")
|
||||
public static class Employee extends AbstractEntity {
|
||||
|
||||
@Embedded
|
||||
private Projects projects;
|
||||
|
||||
@Embedded
|
||||
private ContactDetail contactDetail;
|
||||
|
||||
public void setProjects(Projects projects) {
|
||||
this.projects = projects;
|
||||
}
|
||||
|
||||
public void setContactDetail(ContactDetail contactDetail) {
|
||||
this.contactDetail = contactDetail;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class ContactDetail {
|
||||
private String email;
|
||||
|
||||
@ElementCollection
|
||||
private List<Phone> phones = new ArrayList<>();
|
||||
|
||||
public void addPhone(Phone phone) {
|
||||
this.phones.add( phone );
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class Projects {
|
||||
|
||||
@OneToMany(cascade = CascadeType.PERSIST)
|
||||
private Set<Project> previousProjects = new HashSet<>();
|
||||
|
||||
@ManyToOne(cascade = CascadeType.PERSIST)
|
||||
private Project currentProject;
|
||||
|
||||
public void addPreviousProject(Project project) {
|
||||
this.previousProjects.add( project );
|
||||
}
|
||||
|
||||
public Set<Project> getPreviousProjects() {
|
||||
return previousProjects;
|
||||
}
|
||||
|
||||
public Project getCurrentProject() {
|
||||
return currentProject;
|
||||
}
|
||||
|
||||
public void setCurrentProject(Project project) {
|
||||
this.currentProject = project;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Project")
|
||||
@Table(name = "PROJECT")
|
||||
public static class Project extends AbstractEntity {
|
||||
|
||||
private String name;
|
||||
|
||||
public Project() {
|
||||
}
|
||||
|
||||
public Project(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class Phone {
|
||||
@Column(name = "phone_number")
|
||||
private String number;
|
||||
|
||||
public Phone() {
|
||||
}
|
||||
|
||||
public Phone(String number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return this.number;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
@Table(name = "PERSON")
|
||||
public static class Person extends AbstractEntity {
|
||||
@Embedded
|
||||
private Information information;
|
||||
|
||||
public Information getInformation() {
|
||||
return information;
|
||||
}
|
||||
|
||||
public void setInformation(Information information) {
|
||||
this.information = information;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class Information {
|
||||
@Embedded
|
||||
private ContactDetail infoContactDetail;
|
||||
|
||||
public ContactDetail getInfoContactDetail() {
|
||||
return infoContactDetail;
|
||||
}
|
||||
|
||||
public void setInfoContactDetail(ContactDetail infoContactDetail) {
|
||||
this.infoContactDetail = infoContactDetail;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.jpa.criteria.valuehandlingmode.inline;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.TypedQuery;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
@Jpa(
|
||||
annotatedClasses = DateCompositeCustomTypeTest.Payment.class
|
||||
, properties = @Setting(name = AvailableSettings.CRITERIA_VALUE_HANDLING_MODE, value = "inline")
|
||||
)
|
||||
public class DateCompositeCustomTypeTest {
|
||||
|
||||
@Test
|
||||
public void testDateCompositeCustomType(EntityManagerFactoryScope scope) {
|
||||
final Date date = Date.from( Instant.now() );
|
||||
final Payment payment = new Payment();
|
||||
payment.setAmount( new BigDecimal( 1000 ) );
|
||||
payment.setDate( date );
|
||||
scope.inTransaction(
|
||||
entityManager -> {
|
||||
entityManager.persist( payment );
|
||||
|
||||
CriteriaQuery<Payment> criteria = entityManager.getCriteriaBuilder().createQuery( Payment.class );
|
||||
Root<Payment> rp = criteria.from( Payment.class );
|
||||
Predicate predicate = entityManager.getCriteriaBuilder().equal( rp.get( "date" ), date );
|
||||
criteria.where( predicate );
|
||||
|
||||
TypedQuery<Payment> q = entityManager.createQuery( criteria );
|
||||
List<Payment> payments = q.getResultList();
|
||||
|
||||
assertEquals( 1, payments.size() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "crit_basic_payment")
|
||||
public class Payment {
|
||||
|
||||
private Long id;
|
||||
private BigDecimal amount;
|
||||
private Date date;
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public BigDecimal getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
public void setAmount(BigDecimal amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
@Column(name = "payment_date")
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(Date date) {
|
||||
this.date = date;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.jpa.criteria.valuehandlingmode.inline;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EntityGraph;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.TypedQuery;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Expression;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@Jpa(
|
||||
annotatedClasses = {
|
||||
EntityGraphTest.Bar.class,
|
||||
EntityGraphTest.Baz.class,
|
||||
EntityGraphTest.Foo.class
|
||||
}
|
||||
, properties = @Setting(name = AvailableSettings.CRITERIA_VALUE_HANDLING_MODE, value = "inline")
|
||||
)
|
||||
public class EntityGraphTest {
|
||||
|
||||
@Test
|
||||
public void loadIsMemeberQueriedCollection(EntityManagerFactoryScope scope) {
|
||||
|
||||
Integer id = scope.fromTransaction(
|
||||
entityManager -> {
|
||||
Bar bar = new Bar();
|
||||
entityManager.persist( bar );
|
||||
|
||||
Foo foo = new Foo();
|
||||
foo.bar = bar;
|
||||
bar.foos.add( foo );
|
||||
entityManager.persist( foo );
|
||||
return foo.id;
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
entityManager -> {
|
||||
Foo foo = entityManager.find( Foo.class, id );
|
||||
|
||||
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<Bar> cq = cb.createQuery( Bar.class );
|
||||
Root<Bar> from = cq.from( Bar.class );
|
||||
|
||||
Expression<Set<Foo>> foos = from.get( "foos" );
|
||||
|
||||
cq.where( cb.isMember( foo, foos ) );
|
||||
|
||||
TypedQuery<Bar> query = entityManager.createQuery( cq );
|
||||
|
||||
EntityGraph<Bar> barGraph = entityManager.createEntityGraph( Bar.class );
|
||||
barGraph.addAttributeNodes( "foos" );
|
||||
query.setHint( "javax.persistence.loadgraph", barGraph );
|
||||
|
||||
Bar result = query.getSingleResult();
|
||||
|
||||
assertTrue( Hibernate.isInitialized( result ) );
|
||||
assertTrue( Hibernate.isInitialized( result.foos ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "foo")
|
||||
public static class Foo {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public Integer id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
public Bar bar;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
public Baz baz;
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "bar")
|
||||
public static class Bar {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public Integer id;
|
||||
|
||||
@OneToMany(mappedBy = "bar")
|
||||
public Set<Foo> foos = new HashSet<>();
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "baz")
|
||||
public static class Baz {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
public Integer id;
|
||||
|
||||
@OneToMany(mappedBy = "baz")
|
||||
public Set<Foo> foos = new HashSet<>();
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,471 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.jpa.criteria.valuehandlingmode.inline;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.sql.Date;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.metamodel.model.domain.JpaMetamodel;
|
||||
import org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl;
|
||||
import org.hibernate.query.sqm.tree.predicate.SqmComparisonPredicate;
|
||||
|
||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.Assert;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.AttributeOverride;
|
||||
import jakarta.persistence.AttributeOverrides;
|
||||
import jakarta.persistence.Basic;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.DiscriminatorColumn;
|
||||
import jakarta.persistence.DiscriminatorType;
|
||||
import jakarta.persistence.DiscriminatorValue;
|
||||
import jakarta.persistence.ElementCollection;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.persistence.Embedded;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Inheritance;
|
||||
import jakarta.persistence.InheritanceType;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OrderColumn;
|
||||
import jakarta.persistence.PrimaryKeyJoinColumn;
|
||||
import jakarta.persistence.SecondaryTable;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
import jakarta.persistence.metamodel.EntityType;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@Jpa(
|
||||
annotatedClasses = {
|
||||
EqualityComparisonTest.Address.class,
|
||||
EqualityComparisonTest.Phone.class,
|
||||
EqualityComparisonTest.Product.class
|
||||
}
|
||||
, properties = @Setting(name = AvailableSettings.CRITERIA_VALUE_HANDLING_MODE, value = "inline")
|
||||
)
|
||||
public class EqualityComparisonTest {
|
||||
|
||||
@Test
|
||||
public void testEqualityComparisonEntityConversion(EntityManagerFactoryScope scope) {
|
||||
Address address = new Address( "Street Id", "Fake Street", "Fake City", "Fake State", "Fake Zip" );
|
||||
scope.inTransaction(
|
||||
entityManager -> {
|
||||
Phone phone1 = new Phone( "1", "555", "0001", address );
|
||||
Phone phone2 = new Phone( "2", "555", "0002", address );
|
||||
Phone phone3 = new Phone( "3", "555", "0003", address );
|
||||
Phone phone4 = new Phone( "4", "555", "0004" );
|
||||
|
||||
List<Phone> phones = new ArrayList<>( 3 );
|
||||
phones.add( phone1 );
|
||||
phones.add( phone2 );
|
||||
phones.add( phone3 );
|
||||
|
||||
address.setPhones( phones );
|
||||
entityManager.persist( address );
|
||||
entityManager.persist( phone4 );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
entityManager -> {
|
||||
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
JpaMetamodel mm = (JpaMetamodel) entityManager.getMetamodel();
|
||||
EntityType<Phone> Phone_ = mm.entity( Phone.class );
|
||||
|
||||
CriteriaQuery<Phone> cquery = cb.createQuery( Phone.class );
|
||||
Root<Phone> phone = cquery.from( Phone.class );
|
||||
Predicate predicate = cb.equal(
|
||||
phone.get( Phone_.getSingularAttribute( "address", Address.class ) ),
|
||||
address
|
||||
);
|
||||
cquery.where( predicate );
|
||||
List<Phone> results = entityManager.createQuery( cquery ).getResultList();
|
||||
|
||||
assertEquals( 3, results.size() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqualityComparisonLiteralConversion(EntityManagerFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
entityManager -> {
|
||||
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
JpaMetamodel mm = (JpaMetamodel) entityManager.getMetamodel();
|
||||
|
||||
CriteriaQuery<Integer> cquery = cb.createQuery( Integer.class );
|
||||
Root<Product> product = cquery.from( Product.class );
|
||||
EntityType<Product> Product_ = mm.entity( Product.class );
|
||||
|
||||
cquery.select(
|
||||
cb.toInteger(
|
||||
product.get(
|
||||
Product_.getSingularAttribute( "quantity", Integer.class ) )
|
||||
)
|
||||
);
|
||||
|
||||
SqmComparisonPredicate predicate = (SqmComparisonPredicate) cb.equal(
|
||||
product.get( Product_.getSingularAttribute( "partNumber", Long.class ) ),
|
||||
373767373
|
||||
);
|
||||
Assert.assertEquals( Long.class, predicate.getLeftHandExpression().getJavaType() );
|
||||
cquery.where( predicate );
|
||||
entityManager.createQuery( cquery ).getResultList();
|
||||
|
||||
predicate = (SqmComparisonPredicate) cb.ge(
|
||||
cb.length( product.get( Product_.getSingularAttribute( "name", String.class ) ) ),
|
||||
4L
|
||||
);
|
||||
Assert.assertEquals( Integer.class, predicate.getLeftHandExpression().getJavaType() );
|
||||
cquery.where( predicate );
|
||||
entityManager.createQuery( cquery ).getResultList();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "ADDRESS")
|
||||
public static class Address implements java.io.Serializable {
|
||||
private String id;
|
||||
private String street;
|
||||
private String city;
|
||||
private String state;
|
||||
private String zip;
|
||||
private List<Phone> phones = new ArrayList<>();
|
||||
|
||||
public Address() {
|
||||
}
|
||||
|
||||
public Address(String id, String street, String city, String state, String zip) {
|
||||
this.id = id;
|
||||
this.street = street;
|
||||
this.city = city;
|
||||
this.state = state;
|
||||
this.zip = zip;
|
||||
}
|
||||
|
||||
public Address(
|
||||
String id,
|
||||
String street,
|
||||
String city,
|
||||
String state,
|
||||
String zip,
|
||||
List<Phone> phones) {
|
||||
this.id = id;
|
||||
this.street = street;
|
||||
this.city = city;
|
||||
this.state = state;
|
||||
this.zip = zip;
|
||||
this.phones = phones;
|
||||
}
|
||||
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Column(name = "STREET")
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public void setStreet(String street) {
|
||||
this.street = street;
|
||||
}
|
||||
|
||||
@Column(name = "CITY")
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
@Column(name = "STATE")
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Column(name = "ZIP")
|
||||
public String getZip() {
|
||||
return zip;
|
||||
}
|
||||
|
||||
public void setZip(String zip) {
|
||||
this.zip = zip;
|
||||
}
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "address")
|
||||
@OrderColumn
|
||||
public List<Phone> getPhones() {
|
||||
return phones;
|
||||
}
|
||||
|
||||
public void setPhones(List<Phone> phones) {
|
||||
this.phones = phones;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "PHONE_TABLE")
|
||||
public static class Phone implements java.io.Serializable {
|
||||
public enum Type {LAND_LINE, CELL, FAX, WORK, HOME}
|
||||
|
||||
private String id;
|
||||
private String area;
|
||||
private String number;
|
||||
private Address address;
|
||||
private Set<Phone.Type> types;
|
||||
|
||||
public Phone() {
|
||||
}
|
||||
|
||||
public Phone(String v1, String v2, String v3) {
|
||||
id = v1;
|
||||
area = v2;
|
||||
number = v3;
|
||||
}
|
||||
|
||||
public Phone(String v1, String v2, String v3, Address v4) {
|
||||
id = v1;
|
||||
area = v2;
|
||||
number = v3;
|
||||
address = v4;
|
||||
}
|
||||
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String v) {
|
||||
id = v;
|
||||
}
|
||||
|
||||
@Column(name = "AREA")
|
||||
public String getArea() {
|
||||
return area;
|
||||
}
|
||||
|
||||
public void setArea(String v) {
|
||||
area = v;
|
||||
}
|
||||
|
||||
@Column(name = "PHONE_NUMBER")
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public void setNumber(String v) {
|
||||
number = v;
|
||||
}
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "FK_FOR_ADDRESS")
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(Address a) {
|
||||
address = a;
|
||||
}
|
||||
|
||||
@ElementCollection
|
||||
public Set<Phone.Type> getTypes() {
|
||||
return types;
|
||||
}
|
||||
|
||||
public void setTypes(Set<Phone.Type> types) {
|
||||
this.types = types;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "PRODUCT_TABLE")
|
||||
@SecondaryTable(name = "PRODUCT_DETAILS", pkJoinColumns = @PrimaryKeyJoinColumn(name = "ID"))
|
||||
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
|
||||
@DiscriminatorColumn(name = "PRODUCT_TYPE", discriminatorType = DiscriminatorType.STRING)
|
||||
@DiscriminatorValue("Product")
|
||||
public static class Product {
|
||||
private String id;
|
||||
private String name;
|
||||
private double price;
|
||||
private float rating;
|
||||
private int quantity;
|
||||
private long partNumber;
|
||||
private BigInteger someBigInteger;
|
||||
private BigDecimal someBigDecimal;
|
||||
private String wareHouse;
|
||||
private ShelfLife shelfLife;
|
||||
|
||||
public Product() {
|
||||
}
|
||||
|
||||
public Product(String id, String name, double price, int quantity, long partNumber) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.price = price;
|
||||
this.quantity = quantity;
|
||||
this.partNumber = partNumber;
|
||||
}
|
||||
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Column(name = "NAME")
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Column(name = "PRICE")
|
||||
public double getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public void setPrice(double price) {
|
||||
this.price = price;
|
||||
}
|
||||
|
||||
@Column(name = "QUANTITY")
|
||||
public int getQuantity() {
|
||||
return quantity;
|
||||
}
|
||||
|
||||
public void setQuantity(int v) {
|
||||
this.quantity = v;
|
||||
}
|
||||
|
||||
@Column(name = "PNUM")
|
||||
public long getPartNumber() {
|
||||
return partNumber;
|
||||
}
|
||||
|
||||
public void setPartNumber(long v) {
|
||||
this.partNumber = v;
|
||||
}
|
||||
|
||||
public float getRating() {
|
||||
return rating;
|
||||
}
|
||||
|
||||
public void setRating(float rating) {
|
||||
this.rating = rating;
|
||||
}
|
||||
|
||||
public BigInteger getSomeBigInteger() {
|
||||
return someBigInteger;
|
||||
}
|
||||
|
||||
public void setSomeBigInteger(BigInteger someBigInteger) {
|
||||
this.someBigInteger = someBigInteger;
|
||||
}
|
||||
|
||||
@Column(precision = 10, scale = 3)
|
||||
public BigDecimal getSomeBigDecimal() {
|
||||
return someBigDecimal;
|
||||
}
|
||||
|
||||
public void setSomeBigDecimal(BigDecimal someBigDecimal) {
|
||||
this.someBigDecimal = someBigDecimal;
|
||||
}
|
||||
|
||||
@Column(name = "WHOUSE", nullable = true, table = "PRODUCT_DETAILS")
|
||||
public String getWareHouse() {
|
||||
return wareHouse;
|
||||
}
|
||||
|
||||
public void setWareHouse(String v) {
|
||||
this.wareHouse = v;
|
||||
}
|
||||
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "inceptionDate",
|
||||
column = @Column(name = "INCEPTION", nullable = true)),
|
||||
@AttributeOverride(name = "soldDate",
|
||||
column = @Column(name = "SOLD", nullable = true))
|
||||
})
|
||||
public ShelfLife getShelfLife() {
|
||||
return shelfLife;
|
||||
}
|
||||
|
||||
public void setShelfLife(ShelfLife v) {
|
||||
this.shelfLife = v;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class ShelfLife implements java.io.Serializable {
|
||||
private Date inceptionDate;
|
||||
private Date soldDate;
|
||||
|
||||
public ShelfLife() {
|
||||
}
|
||||
|
||||
public ShelfLife(Date inceptionDate, Date soldDate) {
|
||||
this.inceptionDate = inceptionDate;
|
||||
this.soldDate = soldDate;
|
||||
}
|
||||
|
||||
@Basic
|
||||
public Date getInceptionDate() {
|
||||
return inceptionDate;
|
||||
}
|
||||
|
||||
public void setInceptionDate(Date inceptionDate) {
|
||||
this.inceptionDate = inceptionDate;
|
||||
}
|
||||
|
||||
@Basic
|
||||
public Date getSoldDate() {
|
||||
return soldDate;
|
||||
}
|
||||
|
||||
public void setSoldDate(Date soldDate) {
|
||||
this.soldDate = soldDate;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.jpa.criteria.valuehandlingmode.inline;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.ElementCollection;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.OrderColumn;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
@Jpa(
|
||||
annotatedClasses = {
|
||||
ExpressionsTest.Address.class,
|
||||
ExpressionsTest.Phone.class
|
||||
}
|
||||
, properties = @Setting(name = AvailableSettings.CRITERIA_VALUE_HANDLING_MODE, value = "inline")
|
||||
)
|
||||
public class ExpressionsTest {
|
||||
|
||||
@Test
|
||||
public void testJoinedElementCollectionValuesInTupleList(EntityManagerFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
entityManager -> {
|
||||
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<Phone> criteria = builder.createQuery( Phone.class );
|
||||
Root<Phone> from = criteria.from( Phone.class );
|
||||
criteria.where(
|
||||
from.join( "types" )
|
||||
.in( Collections.singletonList( Phone.Type.WORK ) )
|
||||
);
|
||||
entityManager.createQuery( criteria ).getResultList();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity(name = "Phone")
|
||||
@Table(name = "PHONE_TABLE")
|
||||
public static class Phone implements java.io.Serializable {
|
||||
public enum Type {LAND_LINE, CELL, FAX, WORK, HOME}
|
||||
|
||||
private String id;
|
||||
private String area;
|
||||
private String number;
|
||||
private Address address;
|
||||
private Set<Phone.Type> types;
|
||||
|
||||
public Phone() {
|
||||
}
|
||||
|
||||
public Phone(String v1, String v2, String v3) {
|
||||
id = v1;
|
||||
area = v2;
|
||||
number = v3;
|
||||
}
|
||||
|
||||
public Phone(String v1, String v2, String v3, Address v4) {
|
||||
id = v1;
|
||||
area = v2;
|
||||
number = v3;
|
||||
address = v4;
|
||||
}
|
||||
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String v) {
|
||||
id = v;
|
||||
}
|
||||
|
||||
@Column(name = "AREA")
|
||||
public String getArea() {
|
||||
return area;
|
||||
}
|
||||
|
||||
public void setArea(String v) {
|
||||
area = v;
|
||||
}
|
||||
|
||||
@Column(name = "PHONE_NUMBER")
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public void setNumber(String v) {
|
||||
number = v;
|
||||
}
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "FK_FOR_ADDRESS")
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(Address a) {
|
||||
address = a;
|
||||
}
|
||||
|
||||
@ElementCollection
|
||||
public Set<Phone.Type> getTypes() {
|
||||
return types;
|
||||
}
|
||||
|
||||
public void setTypes(Set<Phone.Type> types) {
|
||||
this.types = types;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "ADDRESS")
|
||||
public static class Address implements java.io.Serializable {
|
||||
private String id;
|
||||
private String street;
|
||||
private String city;
|
||||
private String state;
|
||||
private String zip;
|
||||
private List<Phone> phones = new java.util.ArrayList<Phone>();
|
||||
|
||||
public Address() {
|
||||
}
|
||||
|
||||
public Address(String id, String street, String city, String state, String zip) {
|
||||
this.id = id;
|
||||
this.street = street;
|
||||
this.city = city;
|
||||
this.state = state;
|
||||
this.zip = zip;
|
||||
}
|
||||
|
||||
public Address(
|
||||
String id, String street, String city, String state, String zip,
|
||||
List<Phone> phones) {
|
||||
this.id = id;
|
||||
this.street = street;
|
||||
this.city = city;
|
||||
this.state = state;
|
||||
this.zip = zip;
|
||||
this.phones = phones;
|
||||
}
|
||||
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Column(name = "STREET")
|
||||
public String getStreet() {
|
||||
return street;
|
||||
}
|
||||
|
||||
public void setStreet(String street) {
|
||||
this.street = street;
|
||||
}
|
||||
|
||||
@Column(name = "CITY")
|
||||
public String getCity() {
|
||||
return city;
|
||||
}
|
||||
|
||||
public void setCity(String city) {
|
||||
this.city = city;
|
||||
}
|
||||
|
||||
@Column(name = "STATE")
|
||||
public String getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(String state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Column(name = "ZIP")
|
||||
public String getZip() {
|
||||
return zip;
|
||||
}
|
||||
|
||||
public void setZip(String zip) {
|
||||
this.zip = zip;
|
||||
}
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "address")
|
||||
@OrderColumn
|
||||
public List<Phone> getPhones() {
|
||||
return phones;
|
||||
}
|
||||
|
||||
public void setPhones(List<Phone> phones) {
|
||||
this.phones = phones;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.orm.test.jpa.criteria.valuehandlingmode.inline;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.CollectionTable;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.ElementCollection;
|
||||
import jakarta.persistence.Embeddable;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.MapKeyJoinColumn;
|
||||
import jakarta.persistence.SequenceGenerator;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.MapJoin;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
@Jpa(
|
||||
annotatedClasses = {
|
||||
MapJoinTestWithEmbeddable.Batch.class,
|
||||
MapJoinTestWithEmbeddable.Node.class,
|
||||
MapJoinTestWithEmbeddable.BatchNodeMetadata.class
|
||||
}
|
||||
,properties = @Setting( name = AvailableSettings.CRITERIA_VALUE_HANDLING_MODE, value = "inline")
|
||||
)
|
||||
public class MapJoinTestWithEmbeddable {
|
||||
|
||||
@Test
|
||||
public void testSelectingKeyOfMapJoin(EntityManagerFactoryScope scope) {
|
||||
scope.inTransaction( entityManager -> {
|
||||
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<Node> query = cb.createQuery( Node.class );
|
||||
Root<Batch> root = query.from( Batch.class );
|
||||
|
||||
MapJoin nodes = (MapJoin) root.join( "batchNodeMetadata" );
|
||||
|
||||
query.select( nodes.key() );
|
||||
query.where( cb.equal( root.get( "id" ), 1 ) );
|
||||
|
||||
entityManager.createQuery( query ).getResultList();
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectingValueOfMapJoin(EntityManagerFactoryScope scope) {
|
||||
scope.inTransaction( entityManager -> {
|
||||
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<BatchNodeMetadata> query = cb.createQuery( BatchNodeMetadata.class );
|
||||
Root<Batch> root = query.from( Batch.class );
|
||||
|
||||
MapJoin nodes = (MapJoin) root.join( "batchNodeMetadata" );
|
||||
|
||||
query.select( nodes );
|
||||
query.where( cb.equal( root.get( "id" ), 1 ) );
|
||||
|
||||
entityManager.createQuery( query ).getResultList();
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "batch")
|
||||
public static class Batch implements Serializable {
|
||||
@Id
|
||||
@GeneratedValue(generator = "BatchGen")
|
||||
@SequenceGenerator(name = "BatchGen", sequenceName = "seq_batch", allocationSize = 1)
|
||||
private Long id;
|
||||
|
||||
@ElementCollection
|
||||
@CollectionTable(
|
||||
name = "batch_node",
|
||||
//uniqueConstraints = @UniqueConstraint(columnNames = {"batch_id", "node_id"}),
|
||||
//foreignKey = @ForeignKey,
|
||||
joinColumns = @JoinColumn(name = "batch_id", nullable = false))
|
||||
@MapKeyJoinColumn(name = "node_id")
|
||||
private Map<Node, BatchNodeMetadata> batchNodeMetadata = new HashMap<>();
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "node")
|
||||
public static class Node implements Serializable {
|
||||
@Id
|
||||
@GeneratedValue(generator = "NodeGen")
|
||||
@SequenceGenerator(name = "NodeGen", sequenceName = "seq_node", allocationSize = 1)
|
||||
private Long id;
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class BatchNodeMetadata implements Serializable {
|
||||
|
||||
@Column(nullable = false)
|
||||
@Enumerated(EnumType.STRING)
|
||||
private NodeMigration migrering = NodeMigration.TOTAL;
|
||||
|
||||
public NodeMigration getMigrering() {
|
||||
return migrering;
|
||||
}
|
||||
|
||||
public void setMigrering(NodeMigration migrering) {
|
||||
this.migrering = migrering;
|
||||
}
|
||||
}
|
||||
|
||||
public enum NodeMigration {
|
||||
TOTAL
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.jpa.criteria.valuehandlingmode.inline;
|
||||
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.annotations.Parameter;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.OneToOne;
|
||||
import jakarta.persistence.PrimaryKeyJoinColumn;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
@Jpa(
|
||||
annotatedClasses = { OptionalOneToOneTest.Person.class, OptionalOneToOneTest.PersonAddress.class }
|
||||
,properties = @Setting( name = AvailableSettings.CRITERIA_VALUE_HANDLING_MODE, value = "inline")
|
||||
)
|
||||
public class OptionalOneToOneTest {
|
||||
|
||||
@Test
|
||||
public void testBidirQueryEntityProperty(EntityManagerFactoryScope scope) {
|
||||
|
||||
PersonAddress personAddress = scope.fromTransaction(
|
||||
session -> {
|
||||
PersonAddress address = new PersonAddress();
|
||||
Person person = new Person();
|
||||
address.setPerson( person );
|
||||
person.setPersonAddress( address );
|
||||
|
||||
session.persist( person );
|
||||
session.persist( address );
|
||||
return address;
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction( session -> {
|
||||
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
|
||||
|
||||
CriteriaQuery<Person> criteria = criteriaBuilder.createQuery( Person.class );
|
||||
Root<Person> root = criteria.from( Person.class );
|
||||
criteria.where( criteriaBuilder.equal( root.get( "personAddress" ), personAddress ) );
|
||||
|
||||
session.createQuery( criteria ).getSingleResult();
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity
|
||||
public static class Person {
|
||||
@Id @GeneratedValue(generator = "fk")
|
||||
@GenericGenerator(strategy = "foreign", name = "fk", parameters = @Parameter(name="property", value="personAddress"))
|
||||
private Integer id;
|
||||
|
||||
@PrimaryKeyJoinColumn
|
||||
@OneToOne(optional=true)
|
||||
private PersonAddress personAddress;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public PersonAddress getPersonAddress() {
|
||||
return personAddress;
|
||||
}
|
||||
|
||||
public void setPersonAddress(PersonAddress personAddress) {
|
||||
this.personAddress = personAddress;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Entity
|
||||
public static class PersonAddress {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Integer id;
|
||||
|
||||
@OneToOne(mappedBy="personAddress")
|
||||
private Person person;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Person getPerson() {
|
||||
return person;
|
||||
}
|
||||
|
||||
public void setPerson(Person person) {
|
||||
this.person = person;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.jpa.criteria.valuehandlingmode.inline;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.CockroachDialect;
|
||||
|
||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.JoinColumn;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Path;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@Jpa(
|
||||
annotatedClasses = {
|
||||
PredicateTest.Customer.class,
|
||||
PredicateTest.Order.class
|
||||
}
|
||||
, properties = @Setting(name = AvailableSettings.CRITERIA_VALUE_HANDLING_MODE, value = "inline")
|
||||
)
|
||||
public class PredicateTest {
|
||||
|
||||
@Test
|
||||
@SkipForDialect(dialectClass = CockroachDialect.class, reason = "https://github.com/cockroachdb/cockroach/issues/41943")
|
||||
public void testQuotientConversion(EntityManagerFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
entityManager -> {
|
||||
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<Order> orderCriteria = builder.createQuery( Order.class );
|
||||
Root<Order> orderRoot = orderCriteria.from( Order.class );
|
||||
|
||||
Long longValue = 999999999L;
|
||||
Path<Double> doublePath = orderRoot.get( "totalPrice" );
|
||||
Path<Integer> integerPath = orderRoot.get( "customer" ).get( "age" );
|
||||
|
||||
orderCriteria.select( orderRoot );
|
||||
Predicate p = builder.ge(
|
||||
builder.quot( integerPath, doublePath ),
|
||||
longValue
|
||||
);
|
||||
orderCriteria.where( p );
|
||||
|
||||
List<Order> orders = entityManager.createQuery( orderCriteria ).getResultList();
|
||||
assertTrue( orders.size() == 0 );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "ORDER_TABLE")
|
||||
public static class Order {
|
||||
private String id;
|
||||
private double totalPrice;
|
||||
private Customer customer;
|
||||
|
||||
public Order() {
|
||||
}
|
||||
|
||||
public Order(String id, double totalPrice) {
|
||||
this.id = id;
|
||||
this.totalPrice = totalPrice;
|
||||
}
|
||||
|
||||
public Order(String id, Customer customer) {
|
||||
this.id = id;
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public Order(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Column(name = "TOTALPRICE")
|
||||
public double getTotalPrice() {
|
||||
return totalPrice;
|
||||
}
|
||||
|
||||
public void setTotalPrice(double price) {
|
||||
this.totalPrice = price;
|
||||
}
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "FK4_FOR_CUSTOMER_TABLE")
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
@Table(name = "CUSTOMER_TABLE")
|
||||
public static class Customer {
|
||||
private String id;
|
||||
private String name;
|
||||
private Integer age;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(String id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
// Used by test case for HHH-8699.
|
||||
public Customer(String id, String name, String greeting, Boolean something) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Id
|
||||
@Column(name = "ID")
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String v) {
|
||||
this.id = v;
|
||||
}
|
||||
|
||||
@Column(name = "NAME")
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String v) {
|
||||
this.name = v;
|
||||
}
|
||||
|
||||
@Column(name = "AGE")
|
||||
public Integer getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public void setAge(Integer age) {
|
||||
this.age = age;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.jpa.criteria.valuehandlingmode.inline;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.From;
|
||||
import jakarta.persistence.criteria.JoinType;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
import jakarta.persistence.criteria.Subquery;
|
||||
import jakarta.persistence.metamodel.EntityType;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
@Jpa(
|
||||
annotatedClasses = {
|
||||
SubQueryTest.Site.class,
|
||||
SubQueryTest.Task.class,
|
||||
SubQueryTest.Patient.class
|
||||
}
|
||||
, properties = @Setting(name = AvailableSettings.CRITERIA_VALUE_HANDLING_MODE, value = "inline")
|
||||
)
|
||||
public class SubQueryTest {
|
||||
private Set<Site> validSites;
|
||||
|
||||
private Task taskWithoutPatient;
|
||||
private Task taskWithPatientWithoutSite;
|
||||
private Task taskWithPatient1WithValidSite1;
|
||||
private Task taskWithPatient2WithValidSite1;
|
||||
private Task taskWithPatient3WithValidSite2;
|
||||
private Task taskWithPatientWithInvalidSite;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp(EntityManagerFactoryScope scope) {
|
||||
scope.inTransaction( entityManager -> {
|
||||
final Site validSite1 = new Site();
|
||||
final Site validSite2 = new Site();
|
||||
final Site invalidSite = new Site();
|
||||
|
||||
entityManager.persist( validSite1 );
|
||||
entityManager.persist( validSite2 );
|
||||
entityManager.persist( invalidSite );
|
||||
|
||||
validSites = new HashSet<>( Arrays.asList( validSite1, validSite2 ) );
|
||||
|
||||
final Patient patientWithoutSite = new Patient();
|
||||
final Patient patient1WithValidSite1 = new Patient( validSite1 );
|
||||
final Patient patient2WithValidSite1 = new Patient( validSite1 );
|
||||
final Patient patient3WithValidSite2 = new Patient( validSite2 );
|
||||
final Patient patientWithInvalidSite = new Patient( invalidSite );
|
||||
|
||||
entityManager.persist( patientWithoutSite );
|
||||
entityManager.persist( patient1WithValidSite1 );
|
||||
entityManager.persist( patient2WithValidSite1 );
|
||||
entityManager.persist( patient3WithValidSite2 );
|
||||
entityManager.persist( patientWithInvalidSite );
|
||||
|
||||
taskWithoutPatient = new Task();
|
||||
taskWithoutPatient.description = "taskWithoutPatient";
|
||||
|
||||
taskWithPatientWithoutSite = new Task( patientWithoutSite );
|
||||
taskWithPatientWithoutSite.description = "taskWithPatientWithoutSite";
|
||||
|
||||
taskWithPatient1WithValidSite1 = new Task( patient1WithValidSite1 );
|
||||
taskWithPatient1WithValidSite1.description = "taskWithPatient1WithValidSite1";
|
||||
|
||||
taskWithPatient2WithValidSite1 = new Task( patient2WithValidSite1 );
|
||||
taskWithPatient2WithValidSite1.description = "taskWithPatient2WithValidSite1";
|
||||
|
||||
taskWithPatient3WithValidSite2 = new Task( patient3WithValidSite2 );
|
||||
taskWithPatient3WithValidSite2.description = "taskWithPatient3WithValidSite2";
|
||||
|
||||
taskWithPatientWithInvalidSite = new Task( patientWithInvalidSite );
|
||||
taskWithPatientWithInvalidSite.description = "taskWithPatientWithInvalidSite";
|
||||
|
||||
entityManager.persist( taskWithoutPatient );
|
||||
entityManager.persist( taskWithPatientWithoutSite );
|
||||
entityManager.persist( taskWithPatient1WithValidSite1 );
|
||||
entityManager.persist( taskWithPatient2WithValidSite1 );
|
||||
entityManager.persist( taskWithPatient3WithValidSite2 );
|
||||
entityManager.persist( taskWithPatientWithInvalidSite );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCorrelateSubQueryLeftJoin(EntityManagerFactoryScope scope) {
|
||||
scope.inTransaction( entityManager -> {
|
||||
final CriteriaBuilder builder = entityManager.getCriteriaBuilder();
|
||||
final CriteriaQuery<Task> outerQuery = builder.createQuery( Task.class );
|
||||
final Root<Task> outerTask = outerQuery.from( Task.class );
|
||||
|
||||
final Subquery<Task> subquery = outerQuery.subquery( Task.class );
|
||||
final Root<Task> subtask = subquery.correlate( outerTask );
|
||||
final EntityType<Task> taskEntityType = entityManager.getMetamodel().entity( Task.class );
|
||||
final EntityType<Patient> patientEntityType = entityManager.getMetamodel().entity( Patient.class );
|
||||
final From<Task, Patient> patient = subtask.join(
|
||||
taskEntityType.getSingularAttribute( "patient", Patient.class ),
|
||||
JoinType.LEFT
|
||||
);
|
||||
final From<Patient, Site> site = patient.join(
|
||||
patientEntityType.getSingularAttribute( "site", Site.class ),
|
||||
JoinType.LEFT
|
||||
);
|
||||
outerQuery.where(
|
||||
builder.exists(
|
||||
subquery.select( subtask )
|
||||
.where(
|
||||
builder.or(
|
||||
patient.isNull(),
|
||||
site.in( validSites )
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
final List<Task> tasks = entityManager.createQuery( outerQuery ).getResultList();
|
||||
assertThat( new HashSet<>( tasks ), is( new HashSet<>( Arrays.asList(
|
||||
taskWithoutPatient,
|
||||
taskWithPatient1WithValidSite1,
|
||||
taskWithPatient2WithValidSite1,
|
||||
taskWithPatient3WithValidSite2
|
||||
) ) ) );
|
||||
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "Task")
|
||||
@Table(name = "Task")
|
||||
public static class Task {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
Patient patient;
|
||||
|
||||
String description;
|
||||
|
||||
public Task() {
|
||||
}
|
||||
|
||||
public Task(Patient patient) {
|
||||
this.patient = patient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if ( this == o ) {
|
||||
return true;
|
||||
}
|
||||
if ( o == null || getClass() != o.getClass() ) {
|
||||
return false;
|
||||
}
|
||||
Task task = (Task) o;
|
||||
return id.equals( task.id );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash( id );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format( "Task(id: %d; description: %s)", id, description == null ? "null" : description );
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Patient")
|
||||
@Table(name = "Patient")
|
||||
public static class Patient {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
Site site;
|
||||
|
||||
public Patient() {
|
||||
}
|
||||
|
||||
public Patient(Site site) {
|
||||
this.site = site;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Entity(name = "Site")
|
||||
@Table(name = "Site")
|
||||
public static class Site {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
Long id;
|
||||
|
||||
String name;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue