CriteriaQuery#getParameters() should not return parameters internally created because value handling mode is bind
This commit is contained in:
parent
09299e1f41
commit
5ae3d1e81e
|
@ -274,8 +274,6 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder {
|
|||
@Override
|
||||
<T> JpaParameterExpression<T> parameter(Class<T> paramClass, String name);
|
||||
|
||||
<T> JpaParameterExpression<T> parameter(Class<T> paramClass, T value);
|
||||
|
||||
@Override
|
||||
JpaExpression<String> concat(Expression<String> x, Expression<String> y);
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ import org.hibernate.query.sqm.tree.domain.SqmPluralValuedSimplePath;
|
|||
import org.hibernate.query.sqm.tree.domain.SqmSetJoin;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmSingularJoin;
|
||||
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
|
||||
import org.hibernate.query.sqm.tree.expression.ValueBindJpaCriteriaParameter;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmBinaryArithmetic;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
|
||||
|
@ -996,16 +997,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
|
||||
@Override
|
||||
public <T> JpaCriteriaParameter<T> parameter(Class<T> paramClass, String name) {
|
||||
return (JpaCriteriaParameter<T>) parameter( paramClass, name, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> JpaParameterExpression<T> parameter(Class<T> paramClass, T value) {
|
||||
return parameter( paramClass, null, value );
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> JpaParameterExpression<T> parameter(Class<T> paramClass, String name, T value) {
|
||||
final BasicType<T> basicType = getTypeConfiguration().getBasicTypeForJavaType( paramClass );
|
||||
if ( basicType == null ) {
|
||||
final BindableType<T> parameterType;
|
||||
|
@ -1019,13 +1011,12 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
return new JpaCriteriaParameter<>(
|
||||
name,
|
||||
parameterType,
|
||||
value,
|
||||
true,
|
||||
this
|
||||
);
|
||||
}
|
||||
else {
|
||||
return new JpaCriteriaParameter<>( name, basicType, value, false, this );
|
||||
return new JpaCriteriaParameter<>( name, basicType, false, this );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1419,7 +1410,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
return literal( value, typeInferenceSource );
|
||||
}
|
||||
|
||||
return new JpaCriteriaParameter<>(
|
||||
return new ValueBindJpaCriteriaParameter<>(
|
||||
resolveInferredParameterType( value, typeInferenceSource, getTypeConfiguration() ),
|
||||
value,
|
||||
this
|
||||
|
@ -1456,7 +1447,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
|||
return literal( value );
|
||||
}
|
||||
else {
|
||||
return new JpaCriteriaParameter<>(
|
||||
return new ValueBindJpaCriteriaParameter<>(
|
||||
queryEngine.getTypeConfiguration().getSessionFactory().resolveParameterBindType( value ),
|
||||
value,
|
||||
this
|
||||
|
|
|
@ -33,16 +33,8 @@ public class JpaCriteriaParameter<T>
|
|||
extends AbstractSqmExpression<T>
|
||||
implements SqmParameter<T>, QueryParameterImplementor<T>, DomainResultProducer<T> {
|
||||
private final String name;
|
||||
private final T value;
|
||||
private boolean allowsMultiValuedBinding;
|
||||
|
||||
public JpaCriteriaParameter(
|
||||
BindableType<T> type,
|
||||
boolean allowsMultiValuedBinding,
|
||||
NodeBuilder nodeBuilder) {
|
||||
this( null, type, allowsMultiValuedBinding, nodeBuilder );
|
||||
}
|
||||
|
||||
public JpaCriteriaParameter(
|
||||
String name,
|
||||
BindableType<T> type,
|
||||
|
@ -50,19 +42,6 @@ public class JpaCriteriaParameter<T>
|
|||
NodeBuilder nodeBuilder) {
|
||||
super( toSqmType( type, nodeBuilder ), nodeBuilder );
|
||||
this.name = name;
|
||||
this.value = null;
|
||||
this.allowsMultiValuedBinding = allowsMultiValuedBinding;
|
||||
}
|
||||
|
||||
public JpaCriteriaParameter(
|
||||
String name,
|
||||
BindableType<T> type,
|
||||
T value,
|
||||
boolean allowsMultiValuedBinding,
|
||||
NodeBuilder nodeBuilder) {
|
||||
super( toSqmType( type, nodeBuilder ), nodeBuilder );
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.allowsMultiValuedBinding = allowsMultiValuedBinding;
|
||||
}
|
||||
|
||||
|
@ -75,19 +54,13 @@ public class JpaCriteriaParameter<T>
|
|||
);
|
||||
}
|
||||
|
||||
public JpaCriteriaParameter(BindableType<T> type, T value, NodeBuilder nodeBuilder) {
|
||||
super( toSqmType( type, nodeBuilder ), nodeBuilder );
|
||||
this.name = null;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return value;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -159,13 +132,8 @@ public class JpaCriteriaParameter<T>
|
|||
|
||||
@Override
|
||||
public void appendHqlString(StringBuilder sb) {
|
||||
if ( getName() == null ) {
|
||||
sb.append( value );
|
||||
}
|
||||
else {
|
||||
sb.append( ':' );
|
||||
sb.append( getName() );
|
||||
}
|
||||
sb.append( ':' );
|
||||
sb.append( getName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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.query.sqm.tree.expression;
|
||||
|
||||
import org.hibernate.query.BindableType;
|
||||
import org.hibernate.query.sqm.NodeBuilder;
|
||||
|
||||
/**
|
||||
* It is a JpaCriteriaParameter created from a value when ValueHandlingMode is equal to BIND
|
||||
*
|
||||
* @see org.hibernate.query.criteria.ValueHandlingMode
|
||||
*/
|
||||
public class ValueBindJpaCriteriaParameter<T> extends JpaCriteriaParameter<T>{
|
||||
private final T value;
|
||||
|
||||
public ValueBindJpaCriteriaParameter(
|
||||
BindableType<T> type,
|
||||
T value,
|
||||
NodeBuilder nodeBuilder) {
|
||||
super( null, type, false, nodeBuilder );
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHqlString(StringBuilder sb) {
|
||||
sb.append( value );
|
||||
}
|
||||
|
||||
}
|
|
@ -10,6 +10,8 @@ import java.util.Collections;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jakarta.persistence.Tuple;
|
||||
import jakarta.persistence.criteria.Expression;
|
||||
import jakarta.persistence.criteria.Order;
|
||||
|
@ -26,6 +28,7 @@ import org.hibernate.query.sqm.SemanticQueryWalker;
|
|||
import org.hibernate.query.sqm.SqmQuerySource;
|
||||
import org.hibernate.query.sqm.internal.SqmUtil;
|
||||
import org.hibernate.query.sqm.tree.SqmStatement;
|
||||
import org.hibernate.query.sqm.tree.expression.ValueBindJpaCriteriaParameter;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||
import org.hibernate.query.sqm.tree.from.SqmFromClause;
|
||||
import org.hibernate.query.sqm.tree.jpa.ParameterCollector;
|
||||
|
@ -177,7 +180,10 @@ public class SqmSelectStatement<T> extends AbstractSqmSelectQuery<T> implements
|
|||
//
|
||||
// for a "finalized" set of parameters, use `#resolveParameters` instead
|
||||
assert querySource == SqmQuerySource.CRITERIA;
|
||||
return (Set<ParameterExpression<?>>) (Set<?>) getSqmParameters();
|
||||
final Set<ParameterExpression<?>> sqmParameters = (Set<ParameterExpression<?>>) (Set<?>) getSqmParameters();
|
||||
return sqmParameters.stream()
|
||||
.filter( parameterExpression -> !( parameterExpression instanceof ValueBindJpaCriteriaParameter ) )
|
||||
.collect( Collectors.toSet() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* 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.Collection;
|
||||
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.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.TypedQuery;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Join;
|
||||
import jakarta.persistence.criteria.ParameterExpression;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
import jakarta.persistence.metamodel.EntityType;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@Jpa(
|
||||
annotatedClasses = {
|
||||
CriteriaGetParametersTest.Person.class,
|
||||
CriteriaGetParametersTest.Address.class
|
||||
}
|
||||
// ,
|
||||
// properties = @Setting(name = AvailableSettings.JPA_QUERY_COMPLIANCE, value = "true")
|
||||
)
|
||||
public class CriteriaGetParametersTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setUp(EntityManagerFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
entityManager -> {
|
||||
entityManager.persist( new Person( 1, "Andrea", 5 ) );
|
||||
entityManager.persist( new Person( 2, "Andrea", 35 ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void tearDown(EntityManagerFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
entityManager ->
|
||||
entityManager.createQuery( "delete from Person" ).executeUpdate()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetParameters(EntityManagerFactoryScope scope) {
|
||||
scope.inEntityManager(
|
||||
entityManager -> {
|
||||
final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
|
||||
|
||||
final CriteriaQuery<Person> query = criteriaBuilder.createQuery( Person.class );
|
||||
final Root<Person> person = query.from( Person.class );
|
||||
|
||||
query.select( person );
|
||||
query.where( criteriaBuilder.equal( person.get( "age" ), 30 ) );
|
||||
|
||||
final Set<ParameterExpression<?>> parameters = query.getParameters();
|
||||
|
||||
entityManager.createQuery( query ).getResultList();
|
||||
assertThat( parameters, notNullValue() );
|
||||
assertTrue( parameters.isEmpty() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void likeExpStringExpTest(EntityManagerFactoryScope scope) {
|
||||
scope.inEntityManager(
|
||||
entityManager -> {
|
||||
CriteriaBuilder cbuilder = entityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<Person> cquery = cbuilder.createQuery( Person.class );
|
||||
Root<Person> customer = cquery.from( Person.class );
|
||||
final EntityType<Person> Person_ = entityManager.getMetamodel().entity( Person.class );
|
||||
Join<Person, Address> a = customer.join( Person_.getCollection( "addresses", Address.class ) );
|
||||
cquery.where( cbuilder.like( a.get( "street" ), "sh\\_ll",
|
||||
cbuilder.literal( '\\' )
|
||||
) );
|
||||
cquery.select( customer );
|
||||
TypedQuery<Person> tquery = entityManager.createQuery( cquery );
|
||||
tquery.setMaxResults( 5 );
|
||||
List<Person> clist = tquery.getResultList();
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Entity(name = "Person")
|
||||
@Table(name = "PERSON_TABLE")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
private Integer age;
|
||||
|
||||
@ManyToMany
|
||||
private Collection<Address> addresses;
|
||||
|
||||
Person() {
|
||||
}
|
||||
|
||||
public Person(Integer id, String name, Integer age) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
}
|
||||
|
||||
|
||||
public Collection<Address> getAddresses() {
|
||||
return addresses;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
public static class Address {
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private String street;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue