Skip to content

Commit f78ae8b

Browse files
dreab8Sanne
authored andcommitted
HHH-15113 Exception setting ParameterExpressions on Update Queries
1 parent c3cefd7 commit f78ae8b

File tree

4 files changed

+121
-5
lines changed

4 files changed

+121
-5
lines changed

hibernate-core/src/main/java/org/hibernate/query/criteria/internal/CriteriaUpdateImpl.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import java.util.ArrayList;
1010
import java.util.List;
11+
import javax.persistence.Parameter;
1112
import javax.persistence.criteria.CriteriaUpdate;
1213
import javax.persistence.criteria.Expression;
1314
import javax.persistence.criteria.Path;
@@ -69,9 +70,15 @@ public <Y> CriteriaUpdate<T> set(Path<Y> attributePath, Expression<? extends Y>
6970
@SuppressWarnings("unchecked")
7071
public CriteriaUpdate<T> set(String attributeName, Object value) {
7172
final Path attributePath = getRoot().get( attributeName );
72-
final Expression valueExpression = value == null
73-
? criteriaBuilder().nullLiteral( attributePath.getJavaType() )
74-
: criteriaBuilder().literal( value );
73+
final Expression valueExpression;
74+
if ( value instanceof Expression ) {
75+
valueExpression = (Expression) value;
76+
}
77+
else {
78+
valueExpression = value == null
79+
? criteriaBuilder().nullLiteral( attributePath.getJavaType() )
80+
: criteriaBuilder().literal( value );
81+
}
7582
addAssignment( attributePath, valueExpression );
7683
return this;
7784
}

hibernate-core/src/main/java/org/hibernate/query/criteria/internal/compile/CriteriaCompiler.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.util.HashMap;
1212
import java.util.List;
1313
import java.util.Map;
14+
import javax.persistence.Parameter;
1415
import javax.persistence.TypedQuery;
1516
import javax.persistence.criteria.ParameterExpression;
1617

@@ -22,6 +23,7 @@
2223
import org.hibernate.internal.util.collections.Stack;
2324
import org.hibernate.internal.util.collections.StandardStack;
2425
import org.hibernate.query.criteria.LiteralHandlingMode;
26+
import org.hibernate.query.criteria.internal.expression.ParameterExpressionImpl;
2527
import org.hibernate.query.criteria.internal.expression.function.FunctionExpression;
2628
import org.hibernate.query.spi.QueryImplementor;
2729
import org.hibernate.sql.ast.Clause;
@@ -107,8 +109,9 @@ else if ( criteriaQueryParameter.getPosition() != null ) {
107109
);
108110
}
109111
else {
112+
final String name = generateParameterName();
110113
parameterInfo = new ExplicitParameterInfo(
111-
generateParameterName(),
114+
name,
112115
null,
113116
criteriaQueryParameter.getJavaType()
114117
);
@@ -132,6 +135,9 @@ public Class getJavaType() {
132135
}
133136

134137
public void bind(TypedQuery typedQuery) {
138+
if ( literal instanceof Parameter ) {
139+
return;
140+
}
135141
typedQuery.setParameter( parameterName, literal );
136142
}
137143
};

hibernate-core/src/main/java/org/hibernate/query/criteria/internal/expression/ParameterExpressionImpl.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
public class ParameterExpressionImpl<T>
2424
extends ExpressionImpl<T>
2525
implements ParameterExpression<T>, Serializable {
26-
private final String name;
26+
private String name;
2727
private final Integer position;
2828

2929
public ParameterExpressionImpl(
@@ -75,6 +75,9 @@ public void registerParameters(ParameterRegistry registry) {
7575
@Override
7676
public String render(RenderingContext renderingContext) {
7777
final ExplicitParameterInfo parameterInfo = renderingContext.registerExplicitParameter( this );
78+
if ( name == null && position == null ) {
79+
name = parameterInfo.getName();
80+
}
7881
return parameterInfo.render();
7982
}
8083
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package org.hibernate.jpa.test.query;
2+
3+
import org.hibernate.testing.TestForIssue;
4+
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
5+
import org.hibernate.testing.orm.junit.Jpa;
6+
import org.junit.jupiter.api.Test;
7+
8+
import javax.persistence.Entity;
9+
import javax.persistence.Id;
10+
import javax.persistence.Query;
11+
import javax.persistence.criteria.CriteriaBuilder;
12+
import javax.persistence.criteria.CriteriaUpdate;
13+
import javax.persistence.criteria.ParameterExpression;
14+
import javax.persistence.criteria.Root;
15+
import javax.persistence.metamodel.EntityType;
16+
17+
@Jpa(
18+
annotatedClasses = CriteriaUpdateWithParametersTest.Person.class
19+
)
20+
@TestForIssue( jiraKey = "HHH-15113")
21+
public class CriteriaUpdateWithParametersTest {
22+
23+
@Test
24+
public void testCriteriaUpdate(EntityManagerFactoryScope scope) {
25+
scope.inTransaction(
26+
entityManager -> {
27+
final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
28+
final CriteriaUpdate<Person> criteriaUpdate = criteriaBuilder.createCriteriaUpdate( Person.class );
29+
final Root<Person> root = criteriaUpdate.from( Person.class );
30+
31+
final ParameterExpression<Integer> intValueParameter = criteriaBuilder.parameter( Integer.class );
32+
final ParameterExpression<String> stringValueParameter = criteriaBuilder.parameter( String.class );
33+
34+
final EntityType<Person> personEntityType = entityManager.getMetamodel().entity( Person.class );
35+
36+
criteriaUpdate.set( root.get( personEntityType.getSingularAttribute( "age", Integer.class ) ), intValueParameter );
37+
38+
criteriaUpdate.where( criteriaBuilder.equal(
39+
root.get( personEntityType.getSingularAttribute( "name", String.class ) ),
40+
stringValueParameter
41+
) );
42+
43+
final Query query = entityManager.createQuery( criteriaUpdate );
44+
query.setParameter( intValueParameter, 9 );
45+
query.setParameter( stringValueParameter, "Luigi" );
46+
47+
query.executeUpdate();
48+
}
49+
);
50+
}
51+
52+
@Test
53+
public void testCriteriaUpdate2(EntityManagerFactoryScope scope) {
54+
scope.inTransaction(
55+
entityManager -> {
56+
final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
57+
final CriteriaUpdate<Person> criteriaUpdate = criteriaBuilder.createCriteriaUpdate( Person.class );
58+
final Root<Person> root = criteriaUpdate.from( Person.class );
59+
60+
final ParameterExpression<Integer> intValueParameter = criteriaBuilder.parameter( Integer.class );
61+
final ParameterExpression<String> stringValueParameter = criteriaBuilder.parameter( String.class );
62+
63+
criteriaUpdate.set( "age", intValueParameter );
64+
criteriaUpdate.where( criteriaBuilder.equal( root.get( "name" ), stringValueParameter ) );
65+
66+
final Query query = entityManager.createQuery( criteriaUpdate );
67+
query.setParameter( intValueParameter, 9 );
68+
query.setParameter( stringValueParameter, "Luigi" );
69+
70+
query.executeUpdate();
71+
}
72+
);
73+
}
74+
75+
@Entity(name = "Person")
76+
public static class Person {
77+
78+
@Id
79+
private String id;
80+
81+
private String name;
82+
83+
private Integer age;
84+
85+
public Person() {
86+
}
87+
88+
public String getId() {
89+
return id;
90+
}
91+
92+
public String getName() {
93+
return name;
94+
}
95+
96+
public Integer getAge() {
97+
return age;
98+
}
99+
}
100+
}

0 commit comments

Comments
 (0)