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
|
@Override
|
||||||
<T> JpaParameterExpression<T> parameter(Class<T> paramClass, String name);
|
<T> JpaParameterExpression<T> parameter(Class<T> paramClass, String name);
|
||||||
|
|
||||||
<T> JpaParameterExpression<T> parameter(Class<T> paramClass, T value);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
JpaExpression<String> concat(Expression<String> x, Expression<String> y);
|
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.SqmSetJoin;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmSingularJoin;
|
import org.hibernate.query.sqm.tree.domain.SqmSingularJoin;
|
||||||
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
|
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.SqmBinaryArithmetic;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
|
import org.hibernate.query.sqm.tree.expression.SqmCaseSearched;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
|
import org.hibernate.query.sqm.tree.expression.SqmCaseSimple;
|
||||||
|
@ -996,16 +997,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> JpaCriteriaParameter<T> parameter(Class<T> paramClass, String name) {
|
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 );
|
final BasicType<T> basicType = getTypeConfiguration().getBasicTypeForJavaType( paramClass );
|
||||||
if ( basicType == null ) {
|
if ( basicType == null ) {
|
||||||
final BindableType<T> parameterType;
|
final BindableType<T> parameterType;
|
||||||
|
@ -1019,13 +1011,12 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
||||||
return new JpaCriteriaParameter<>(
|
return new JpaCriteriaParameter<>(
|
||||||
name,
|
name,
|
||||||
parameterType,
|
parameterType,
|
||||||
value,
|
|
||||||
true,
|
true,
|
||||||
this
|
this
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
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 literal( value, typeInferenceSource );
|
||||||
}
|
}
|
||||||
|
|
||||||
return new JpaCriteriaParameter<>(
|
return new ValueBindJpaCriteriaParameter<>(
|
||||||
resolveInferredParameterType( value, typeInferenceSource, getTypeConfiguration() ),
|
resolveInferredParameterType( value, typeInferenceSource, getTypeConfiguration() ),
|
||||||
value,
|
value,
|
||||||
this
|
this
|
||||||
|
@ -1456,7 +1447,7 @@ public class SqmCriteriaNodeBuilder implements NodeBuilder, SqmCreationContext,
|
||||||
return literal( value );
|
return literal( value );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return new JpaCriteriaParameter<>(
|
return new ValueBindJpaCriteriaParameter<>(
|
||||||
queryEngine.getTypeConfiguration().getSessionFactory().resolveParameterBindType( value ),
|
queryEngine.getTypeConfiguration().getSessionFactory().resolveParameterBindType( value ),
|
||||||
value,
|
value,
|
||||||
this
|
this
|
||||||
|
|
|
@ -33,16 +33,8 @@ public class JpaCriteriaParameter<T>
|
||||||
extends AbstractSqmExpression<T>
|
extends AbstractSqmExpression<T>
|
||||||
implements SqmParameter<T>, QueryParameterImplementor<T>, DomainResultProducer<T> {
|
implements SqmParameter<T>, QueryParameterImplementor<T>, DomainResultProducer<T> {
|
||||||
private final String name;
|
private final String name;
|
||||||
private final T value;
|
|
||||||
private boolean allowsMultiValuedBinding;
|
private boolean allowsMultiValuedBinding;
|
||||||
|
|
||||||
public JpaCriteriaParameter(
|
|
||||||
BindableType<T> type,
|
|
||||||
boolean allowsMultiValuedBinding,
|
|
||||||
NodeBuilder nodeBuilder) {
|
|
||||||
this( null, type, allowsMultiValuedBinding, nodeBuilder );
|
|
||||||
}
|
|
||||||
|
|
||||||
public JpaCriteriaParameter(
|
public JpaCriteriaParameter(
|
||||||
String name,
|
String name,
|
||||||
BindableType<T> type,
|
BindableType<T> type,
|
||||||
|
@ -50,19 +42,6 @@ public class JpaCriteriaParameter<T>
|
||||||
NodeBuilder nodeBuilder) {
|
NodeBuilder nodeBuilder) {
|
||||||
super( toSqmType( type, nodeBuilder ), nodeBuilder );
|
super( toSqmType( type, nodeBuilder ), nodeBuilder );
|
||||||
this.name = name;
|
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;
|
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
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public T getValue() {
|
public T getValue() {
|
||||||
return value;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -159,13 +132,8 @@ public class JpaCriteriaParameter<T>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void appendHqlString(StringBuilder sb) {
|
public void appendHqlString(StringBuilder sb) {
|
||||||
if ( getName() == null ) {
|
sb.append( ':' );
|
||||||
sb.append( value );
|
sb.append( getName() );
|
||||||
}
|
|
||||||
else {
|
|
||||||
sb.append( ':' );
|
|
||||||
sb.append( getName() );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import jakarta.persistence.Tuple;
|
import jakarta.persistence.Tuple;
|
||||||
import jakarta.persistence.criteria.Expression;
|
import jakarta.persistence.criteria.Expression;
|
||||||
import jakarta.persistence.criteria.Order;
|
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.SqmQuerySource;
|
||||||
import org.hibernate.query.sqm.internal.SqmUtil;
|
import org.hibernate.query.sqm.internal.SqmUtil;
|
||||||
import org.hibernate.query.sqm.tree.SqmStatement;
|
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.expression.SqmParameter;
|
||||||
import org.hibernate.query.sqm.tree.from.SqmFromClause;
|
import org.hibernate.query.sqm.tree.from.SqmFromClause;
|
||||||
import org.hibernate.query.sqm.tree.jpa.ParameterCollector;
|
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
|
// for a "finalized" set of parameters, use `#resolveParameters` instead
|
||||||
assert querySource == SqmQuerySource.CRITERIA;
|
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
|
@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