Support list parameters for JPQL query (rollback our changes and use EL capability). #PL-5846 #PL-6108

This commit is contained in:
Konstantin Krivopustov 2015-10-07 06:58:47 +00:00
parent 24650c4d9f
commit 069b647bb9
10 changed files with 64 additions and 82 deletions

View File

@ -398,7 +398,7 @@ public class DataManagerBean implements DataManager {
View view = new View(baseAttributeValueView, null, false)
.addProperty("categoryAttribute", new View(baseAttributeView, null, false).addProperty("category"));
return em.createQuery("select cav from sys$CategoryAttributeValue cav where cav.entityId in (:ids)", CategoryAttributeValue.class)
return em.createQuery("select cav from sys$CategoryAttributeValue cav where cav.entityId in :ids", CategoryAttributeValue.class)
.setParameter("ids", entityIds)
.setView(view)
.getResultList();

View File

@ -7,16 +7,15 @@ package com.haulmont.cuba.core.sys;
import com.google.common.collect.Iterables;
import com.haulmont.bali.util.ReflectionHelper;
import com.haulmont.cuba.core.TypedQuery;
import com.haulmont.cuba.core.entity.BaseEntity;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.*;
import com.haulmont.cuba.core.sys.persistence.DbmsFeatures;
import com.haulmont.cuba.core.sys.persistence.DbmsSpecificFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.persistence.config.HintValues;
import org.eclipse.persistence.config.QueryHints;
import org.eclipse.persistence.jpa.JpaQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import javax.persistence.FlushModeType;
@ -135,8 +134,6 @@ public class QueryImpl<T> implements TypedQuery<T> {
for (Param param : params) {
if (param.value instanceof String && ((String) param.value).startsWith("(?i)"))
result = replaceCaseInsensitiveParam(result, param);
if (param.value instanceof Collection)
result = replaceCollectionParam(result, param);
}
return result;
@ -164,27 +161,13 @@ public class QueryImpl<T> implements TypedQuery<T> {
return result;
}
private String replaceCollectionParam(String queryStr, Param param) {
if (!(param.name instanceof String))
throw new UnsupportedOperationException("Only named collection parameters are supported");
Collection collection = (Collection) param.value;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < collection.size(); i++) {
sb.append(":").append(param.name).append(i+1);
if (i < collection.size() - 1)
sb.append(",");
}
return queryStr.replace(":" + param.name, sb.toString());
}
private void addMacroParams(javax.persistence.TypedQuery jpaQuery) {
if (macroHandlers != null) {
for (QueryMacroHandler handler : macroHandlers) {
Map<String, Object> namedParams = new HashMap<>();
for (Param param : params) {
if (param.name instanceof String && !(param.value instanceof Collection))
if (param.name instanceof String)
namedParams.put((String) param.name, param.value);
}
handler.setQueryParams(namedParams);
@ -263,20 +246,25 @@ public class QueryImpl<T> implements TypedQuery<T> {
checkState();
if (implicitConversions) {
if (value instanceof Entity)
value = ((BaseEntity) value).getId();
else if (value instanceof Collection) {
List<Object> list = new ArrayList<>(((Collection) value).size());
for (Object obj : ((Collection) value)) {
list.add(obj instanceof Entity ? ((Entity) obj).getId() : obj);
}
value = list;
}
value = handleImplicitConversions(value);
}
params.add(new Param(name, value));
return this;
}
private Object handleImplicitConversions(Object value) {
if (value instanceof Entity)
value = ((Entity) value).getId();
else if (value instanceof Collection) {
List<Object> list = new ArrayList<>(((Collection) value).size());
for (Object obj : ((Collection) value)) {
list.add(obj instanceof Entity ? ((Entity) obj).getId() : obj);
}
value = list;
}
return value;
}
@Override
public TypedQuery<T> setParameter(String name, Date value, TemporalType temporalType) {
checkState();
@ -298,10 +286,11 @@ public class QueryImpl<T> implements TypedQuery<T> {
try {
value = ReflectionHelper.newInstance(c, value);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
throw new RuntimeException("Error setting parameter value", e);
}
} else if (implicitConversions && value instanceof Entity)
value = ((BaseEntity) value).getId();
} else if (implicitConversions) {
value = handleImplicitConversions(value);
}
params.add(new Param(position, value));
return this;
@ -405,29 +394,15 @@ public class QueryImpl<T> implements TypedQuery<T> {
public void apply(JpaQuery query) {
if (temporalType != null) {
if (name instanceof Integer) {
if (name instanceof Integer)
query.setParameter((int) name, (Date) value, temporalType);
} else {
else
query.setParameter((String) name, (Date) value, temporalType);
}
} else {
if (name instanceof Integer) {
if (name instanceof Integer)
query.setParameter((int) name, value);
} else {
if (value instanceof Collection) {
applyCollection(query, (String) name, (Collection) value);
} else {
query.setParameter((String) name, value);
}
}
}
}
private void applyCollection(JpaQuery query, String name, Collection collection) {
int i = 1;
for (Object value : collection) {
query.setParameter(name + i, value);
i++;
else
query.setParameter((String) name, value);
}
}

View File

@ -125,7 +125,7 @@ public class UserManagementServiceBean implements UserManagementService {
throw new IllegalStateException("Could not found target access group with id: " + targetAccessGroupId);
}
TypedQuery<User> query = em.createQuery("select u from sec$User u where u.id in (:userIds)", User.class);
TypedQuery<User> query = em.createQuery("select u from sec$User u where u.id in :userIds", User.class);
query.setParameter("userIds", userIds);
query.setViewName(MOVE_USER_TO_GROUP_VIEW);
@ -232,7 +232,7 @@ public class UserManagementServiceBean implements UserManagementService {
try {
EntityManager em = persistence.getEntityManager();
Query query = em.createQuery("delete from sec$RememberMeToken rt where rt.user.id in (:userIds)");
Query query = em.createQuery("delete from sec$RememberMeToken rt where rt.user.id in :userIds");
query.setParameter("userIds", userIds);
query.executeUpdate();
@ -445,7 +445,7 @@ public class UserManagementServiceBean implements UserManagementService {
try {
EntityManager em = persistence.getEntityManager();
TypedQuery<User> query = em.createQuery("select u from sec$User u where u.id in (:userIds)", User.class);
TypedQuery<User> query = em.createQuery("select u from sec$User u where u.id in :userIds", User.class);
query.setParameter("userIds", userIds);
query.setViewName(RESET_PASSWORD_VIEW);

View File

@ -304,7 +304,7 @@ public class QueryTest extends CubaTestCase {
public void testListParameter() throws Exception {
try (Transaction tx = persistence.createTransaction()) {
TypedQuery<User> query = persistence.getEntityManager().createQuery(
"select u from sec$User u where u.id in (:ids) order by u.createTs", User.class);
"select u from sec$User u where u.id in :ids order by u.createTs", User.class);
query.setParameter("ids", Arrays.asList(UUID.fromString("60885987-1b61-4247-94c7-dff348347f93"), userId, user2Id));
List<User> list = query.getResultList();
assertEquals(3, list.size());
@ -326,7 +326,7 @@ public class QueryTest extends CubaTestCase {
try (Transaction tx = persistence.createTransaction()) {
TypedQuery<User> query = persistence.getEntityManager().createQuery(
"select u from sec$User u where u.id in (:ids) order by u.createTs", User.class);
"select u from sec$User u where u.id in :ids order by u.createTs", User.class);
query.setParameter("ids", Arrays.asList(user1, user2, user3));
List<User> list = query.getResultList();
assertEquals(3, list.size());
@ -334,18 +334,26 @@ public class QueryTest extends CubaTestCase {
tx.commit();
}
// Positional parameters are not supported
// Positional parameters
try (Transaction tx = persistence.createTransaction()) {
TypedQuery<User> query = persistence.getEntityManager().createQuery(
"select u from sec$User u where u.id in (?1) order by u.createTs", User.class);
"select u from sec$User u where u.id in ?1 order by u.createTs", User.class);
query.setParameter(1, Arrays.asList(user1.getId(), user2.getId(), user3.getId()));
List<User> list = query.getResultList();
assertEquals(3, list.size());
tx.commit();
}
// Positional parameters with implicit conversion
try (Transaction tx = persistence.createTransaction()) {
TypedQuery<User> query = persistence.getEntityManager().createQuery(
"select u from sec$User u where u.id in ?1 order by u.createTs", User.class);
query.setParameter(1, Arrays.asList(user1, user2, user3));
try {
query.getResultList();
fail();
} catch (UnsupportedOperationException e) {
// ok
}
List<User> list = query.getResultList();
assertEquals(3, list.size());
tx.commit();
}

View File

@ -6,7 +6,7 @@
package com.haulmont.cuba.core.global;
import com.haulmont.cuba.core.sys.jpql.DomainModel;
import com.haulmont.cuba.core.sys.jpql.ErrorsFoundException;
import com.haulmont.cuba.core.sys.jpql.QueryErrorsFoundException;
import com.haulmont.cuba.core.sys.jpql.model.Entity;
import com.haulmont.cuba.core.sys.jpql.model.EntityBuilder;
import com.haulmont.cuba.core.sys.jpql.model.EntityImpl;
@ -602,7 +602,7 @@ public class QueryTransformerAstBasedTest {
new QueryTransformerAstBased(model,
"select h from sec$GroupHierarchy h join h.parent.constraints c group by c.level order by c.level having c.level > 0");
fail("Incorrectly placed 'having' passed");
} catch (ErrorsFoundException e) {
} catch (QueryErrorsFoundException e) {
}
}
@ -614,7 +614,7 @@ public class QueryTransformerAstBasedTest {
new QueryTransformerAstBased(model,
"select h from sec$GroupHierarchy h join h.parent.constraints");
fail("Not named join variable passed");
} catch (ErrorsFoundException e) {
} catch (QueryErrorsFoundException e) {
}
}

View File

@ -108,14 +108,14 @@ public class QueryTransformerSoftDeleteBugsTest extends TestCase {
QueryTransformerRegex transformer = new QueryTransformerRegex(
"select j from taxi$IndividualTelephone it, taxi$Job j\n" +
"where it.telephone like :phoneNumber and it.individual.id = j.caller.id\n" +
"and j.executionStatus not in (:notActiveStatuses)");
"and j.executionStatus not in :notActiveStatuses");
transformer.addWhere("{E}.deleteTs is null");
String res = transformer.getResult();
assertEquals(
"select j from taxi$IndividualTelephone it, taxi$Job j\n" +
"where it.telephone like :phoneNumber and it.individual.id = j.caller.id\n" +
"and j.executionStatus not in (:notActiveStatuses) and (it.deleteTs is null)",
"and j.executionStatus not in :notActiveStatuses and (it.deleteTs is null)",
res);
}
}

View File

@ -12,13 +12,14 @@ import java.util.List;
* @author chevelev
* @version $Id$
*/
public class ErrorsFoundException extends RuntimeException{
public class QueryErrorsFoundException extends RuntimeException{
private List<ErrorRec> errorRecs;
public ErrorsFoundException() {
public QueryErrorsFoundException() {
}
public ErrorsFoundException(String message, List<ErrorRec> errorRecs) {
public QueryErrorsFoundException(String message, List<ErrorRec> errorRecs) {
super(message);
this.errorRecs = new ArrayList<>(errorRecs);
}
@ -28,11 +29,11 @@ public class ErrorsFoundException extends RuntimeException{
}
@Override
public String toString() {
String result = "";
public String getMessage() {
String message = super.getMessage();
for (ErrorRec rec : errorRecs) {
result += rec + "\n";
message += "\n" + rec;
}
return result;
return message;
}
}

View File

@ -69,7 +69,7 @@ public class QueryTransformerAstBased implements QueryTransformer {
}
if (!errors.isEmpty()) {
throw new ErrorsFoundException("Errors found", errors);
throw new QueryErrorsFoundException("Errors found", errors);
}
}

View File

@ -150,8 +150,6 @@ public class BulkEditorWindow extends AbstractWindow {
datasource.setAllowCommit(false);
createDataComponents();
datasource.refresh();
}
protected void createDataComponents() {
@ -552,7 +550,7 @@ public class BulkEditorWindow extends AbstractWindow {
}
protected List<Entity> loadItems(View view) {
LoadContext lc = new LoadContext(metaClass);
LoadContext<Entity> lc = new LoadContext<>(metaClass);
lc.setSoftDeletion(false);
List<UUID> ids = new ArrayList<>();

View File

@ -41,7 +41,7 @@ public class UserSetHelper {
String listOfId = createIdsString(ids);
String randomName = RandomStringUtils.randomAlphabetic(10);
condition.addText(entityAlias + ".id in (:component$" + componentId + "." + randomName + ")");
condition.addText(entityAlias + ".id in :component$" + componentId + "." + randomName);
Element param = condition.addElement("param");
param.addAttribute("name", "component$" + componentId + "." + randomName);