HHH-15113 Exception setting ParameterExpressions on Update Queries

This commit is contained in:
Andrea Boriero 2022-03-09 15:19:22 +01:00 committed by Sanne Grinovero
parent c3cefd74ca
commit f78ae8b4c6
4 changed files with 121 additions and 5 deletions

View File

@ -8,6 +8,7 @@ package org.hibernate.query.criteria.internal;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Parameter;
import javax.persistence.criteria.CriteriaUpdate;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Path;
@ -69,9 +70,15 @@ public class CriteriaUpdateImpl<T> extends AbstractManipulationCriteriaQuery<T>
@SuppressWarnings("unchecked")
public CriteriaUpdate<T> set(String attributeName, Object value) {
final Path attributePath = getRoot().get( attributeName );
final Expression valueExpression = value == null
final Expression valueExpression;
if ( value instanceof Expression ) {
valueExpression = (Expression) value;
}
else {
valueExpression = value == null
? criteriaBuilder().nullLiteral( attributePath.getJavaType() )
: criteriaBuilder().literal( value );
}
addAssignment( attributePath, valueExpression );
return this;
}

View File

@ -11,6 +11,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.Parameter;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.ParameterExpression;
@ -22,6 +23,7 @@ import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.internal.util.collections.StandardStack;
import org.hibernate.query.criteria.LiteralHandlingMode;
import org.hibernate.query.criteria.internal.expression.ParameterExpressionImpl;
import org.hibernate.query.criteria.internal.expression.function.FunctionExpression;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.sql.ast.Clause;
@ -107,8 +109,9 @@ public class CriteriaCompiler implements Serializable {
);
}
else {
final String name = generateParameterName();
parameterInfo = new ExplicitParameterInfo(
generateParameterName(),
name,
null,
criteriaQueryParameter.getJavaType()
);
@ -132,6 +135,9 @@ public class CriteriaCompiler implements Serializable {
}
public void bind(TypedQuery typedQuery) {
if ( literal instanceof Parameter ) {
return;
}
typedQuery.setParameter( parameterName, literal );
}
};

View File

@ -23,7 +23,7 @@ import org.hibernate.query.criteria.internal.compile.RenderingContext;
public class ParameterExpressionImpl<T>
extends ExpressionImpl<T>
implements ParameterExpression<T>, Serializable {
private final String name;
private String name;
private final Integer position;
public ParameterExpressionImpl(
@ -75,6 +75,9 @@ public class ParameterExpressionImpl<T>
@Override
public String render(RenderingContext renderingContext) {
final ExplicitParameterInfo parameterInfo = renderingContext.registerExplicitParameter( this );
if ( name == null && position == null ) {
name = parameterInfo.getName();
}
return parameterInfo.render();
}
}

View File

@ -0,0 +1,100 @@
package org.hibernate.jpa.test.query;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.Jpa;
import org.junit.jupiter.api.Test;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaUpdate;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.EntityType;
@Jpa(
annotatedClasses = CriteriaUpdateWithParametersTest.Person.class
)
@TestForIssue( jiraKey = "HHH-15113")
public class CriteriaUpdateWithParametersTest {
@Test
public void testCriteriaUpdate(EntityManagerFactoryScope scope) {
scope.inTransaction(
entityManager -> {
final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
final CriteriaUpdate<Person> criteriaUpdate = criteriaBuilder.createCriteriaUpdate( Person.class );
final Root<Person> root = criteriaUpdate.from( Person.class );
final ParameterExpression<Integer> intValueParameter = criteriaBuilder.parameter( Integer.class );
final ParameterExpression<String> stringValueParameter = criteriaBuilder.parameter( String.class );
final EntityType<Person> personEntityType = entityManager.getMetamodel().entity( Person.class );
criteriaUpdate.set( root.get( personEntityType.getSingularAttribute( "age", Integer.class ) ), intValueParameter );
criteriaUpdate.where( criteriaBuilder.equal(
root.get( personEntityType.getSingularAttribute( "name", String.class ) ),
stringValueParameter
) );
final Query query = entityManager.createQuery( criteriaUpdate );
query.setParameter( intValueParameter, 9 );
query.setParameter( stringValueParameter, "Luigi" );
query.executeUpdate();
}
);
}
@Test
public void testCriteriaUpdate2(EntityManagerFactoryScope scope) {
scope.inTransaction(
entityManager -> {
final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
final CriteriaUpdate<Person> criteriaUpdate = criteriaBuilder.createCriteriaUpdate( Person.class );
final Root<Person> root = criteriaUpdate.from( Person.class );
final ParameterExpression<Integer> intValueParameter = criteriaBuilder.parameter( Integer.class );
final ParameterExpression<String> stringValueParameter = criteriaBuilder.parameter( String.class );
criteriaUpdate.set( "age", intValueParameter );
criteriaUpdate.where( criteriaBuilder.equal( root.get( "name" ), stringValueParameter ) );
final Query query = entityManager.createQuery( criteriaUpdate );
query.setParameter( intValueParameter, 9 );
query.setParameter( stringValueParameter, "Luigi" );
query.executeUpdate();
}
);
}
@Entity(name = "Person")
public static class Person {
@Id
private String id;
private String name;
private Integer age;
public Person() {
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
}
}