mirror of
https://gitee.com/jmix/cuba.git
synced 2024-12-04 20:28:00 +08:00
Support list parameters for JPQL query (rollback our changes and use EL capability). #PL-5846 #PL-6108
This commit is contained in:
parent
24650c4d9f
commit
069b647bb9
@ -398,7 +398,7 @@ public class DataManagerBean implements DataManager {
|
|||||||
View view = new View(baseAttributeValueView, null, false)
|
View view = new View(baseAttributeValueView, null, false)
|
||||||
.addProperty("categoryAttribute", new View(baseAttributeView, null, false).addProperty("category"));
|
.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)
|
.setParameter("ids", entityIds)
|
||||||
.setView(view)
|
.setView(view)
|
||||||
.getResultList();
|
.getResultList();
|
||||||
|
@ -7,16 +7,15 @@ package com.haulmont.cuba.core.sys;
|
|||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.haulmont.bali.util.ReflectionHelper;
|
import com.haulmont.bali.util.ReflectionHelper;
|
||||||
import com.haulmont.cuba.core.TypedQuery;
|
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.entity.Entity;
|
||||||
import com.haulmont.cuba.core.global.*;
|
import com.haulmont.cuba.core.global.*;
|
||||||
import com.haulmont.cuba.core.sys.persistence.DbmsFeatures;
|
import com.haulmont.cuba.core.sys.persistence.DbmsFeatures;
|
||||||
import com.haulmont.cuba.core.sys.persistence.DbmsSpecificFactory;
|
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.HintValues;
|
||||||
import org.eclipse.persistence.config.QueryHints;
|
import org.eclipse.persistence.config.QueryHints;
|
||||||
import org.eclipse.persistence.jpa.JpaQuery;
|
import org.eclipse.persistence.jpa.JpaQuery;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.persistence.FlushModeType;
|
import javax.persistence.FlushModeType;
|
||||||
@ -135,8 +134,6 @@ public class QueryImpl<T> implements TypedQuery<T> {
|
|||||||
for (Param param : params) {
|
for (Param param : params) {
|
||||||
if (param.value instanceof String && ((String) param.value).startsWith("(?i)"))
|
if (param.value instanceof String && ((String) param.value).startsWith("(?i)"))
|
||||||
result = replaceCaseInsensitiveParam(result, param);
|
result = replaceCaseInsensitiveParam(result, param);
|
||||||
if (param.value instanceof Collection)
|
|
||||||
result = replaceCollectionParam(result, param);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -164,27 +161,13 @@ public class QueryImpl<T> implements TypedQuery<T> {
|
|||||||
return result;
|
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) {
|
private void addMacroParams(javax.persistence.TypedQuery jpaQuery) {
|
||||||
if (macroHandlers != null) {
|
if (macroHandlers != null) {
|
||||||
for (QueryMacroHandler handler : macroHandlers) {
|
for (QueryMacroHandler handler : macroHandlers) {
|
||||||
|
|
||||||
Map<String, Object> namedParams = new HashMap<>();
|
Map<String, Object> namedParams = new HashMap<>();
|
||||||
for (Param param : params) {
|
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);
|
namedParams.put((String) param.name, param.value);
|
||||||
}
|
}
|
||||||
handler.setQueryParams(namedParams);
|
handler.setQueryParams(namedParams);
|
||||||
@ -263,20 +246,25 @@ public class QueryImpl<T> implements TypedQuery<T> {
|
|||||||
checkState();
|
checkState();
|
||||||
|
|
||||||
if (implicitConversions) {
|
if (implicitConversions) {
|
||||||
if (value instanceof Entity)
|
value = handleImplicitConversions(value);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
params.add(new Param(name, value));
|
params.add(new Param(name, value));
|
||||||
return this;
|
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
|
@Override
|
||||||
public TypedQuery<T> setParameter(String name, Date value, TemporalType temporalType) {
|
public TypedQuery<T> setParameter(String name, Date value, TemporalType temporalType) {
|
||||||
checkState();
|
checkState();
|
||||||
@ -298,10 +286,11 @@ public class QueryImpl<T> implements TypedQuery<T> {
|
|||||||
try {
|
try {
|
||||||
value = ReflectionHelper.newInstance(c, value);
|
value = ReflectionHelper.newInstance(c, value);
|
||||||
} catch (NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException("Error setting parameter value", e);
|
||||||
}
|
}
|
||||||
} else if (implicitConversions && value instanceof Entity)
|
} else if (implicitConversions) {
|
||||||
value = ((BaseEntity) value).getId();
|
value = handleImplicitConversions(value);
|
||||||
|
}
|
||||||
|
|
||||||
params.add(new Param(position, value));
|
params.add(new Param(position, value));
|
||||||
return this;
|
return this;
|
||||||
@ -405,29 +394,15 @@ public class QueryImpl<T> implements TypedQuery<T> {
|
|||||||
|
|
||||||
public void apply(JpaQuery query) {
|
public void apply(JpaQuery query) {
|
||||||
if (temporalType != null) {
|
if (temporalType != null) {
|
||||||
if (name instanceof Integer) {
|
if (name instanceof Integer)
|
||||||
query.setParameter((int) name, (Date) value, temporalType);
|
query.setParameter((int) name, (Date) value, temporalType);
|
||||||
} else {
|
else
|
||||||
query.setParameter((String) name, (Date) value, temporalType);
|
query.setParameter((String) name, (Date) value, temporalType);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (name instanceof Integer) {
|
if (name instanceof Integer)
|
||||||
query.setParameter((int) name, value);
|
query.setParameter((int) name, value);
|
||||||
} else {
|
else
|
||||||
if (value instanceof Collection) {
|
query.setParameter((String) name, value);
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ public class UserManagementServiceBean implements UserManagementService {
|
|||||||
throw new IllegalStateException("Could not found target access group with id: " + targetAccessGroupId);
|
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.setParameter("userIds", userIds);
|
||||||
query.setViewName(MOVE_USER_TO_GROUP_VIEW);
|
query.setViewName(MOVE_USER_TO_GROUP_VIEW);
|
||||||
|
|
||||||
@ -232,7 +232,7 @@ public class UserManagementServiceBean implements UserManagementService {
|
|||||||
try {
|
try {
|
||||||
EntityManager em = persistence.getEntityManager();
|
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.setParameter("userIds", userIds);
|
||||||
query.executeUpdate();
|
query.executeUpdate();
|
||||||
|
|
||||||
@ -445,7 +445,7 @@ public class UserManagementServiceBean implements UserManagementService {
|
|||||||
try {
|
try {
|
||||||
EntityManager em = persistence.getEntityManager();
|
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.setParameter("userIds", userIds);
|
||||||
query.setViewName(RESET_PASSWORD_VIEW);
|
query.setViewName(RESET_PASSWORD_VIEW);
|
||||||
|
|
||||||
|
@ -304,7 +304,7 @@ public class QueryTest extends CubaTestCase {
|
|||||||
public void testListParameter() throws Exception {
|
public void testListParameter() throws Exception {
|
||||||
try (Transaction tx = persistence.createTransaction()) {
|
try (Transaction tx = persistence.createTransaction()) {
|
||||||
TypedQuery<User> query = persistence.getEntityManager().createQuery(
|
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));
|
query.setParameter("ids", Arrays.asList(UUID.fromString("60885987-1b61-4247-94c7-dff348347f93"), userId, user2Id));
|
||||||
List<User> list = query.getResultList();
|
List<User> list = query.getResultList();
|
||||||
assertEquals(3, list.size());
|
assertEquals(3, list.size());
|
||||||
@ -326,7 +326,7 @@ public class QueryTest extends CubaTestCase {
|
|||||||
|
|
||||||
try (Transaction tx = persistence.createTransaction()) {
|
try (Transaction tx = persistence.createTransaction()) {
|
||||||
TypedQuery<User> query = persistence.getEntityManager().createQuery(
|
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));
|
query.setParameter("ids", Arrays.asList(user1, user2, user3));
|
||||||
List<User> list = query.getResultList();
|
List<User> list = query.getResultList();
|
||||||
assertEquals(3, list.size());
|
assertEquals(3, list.size());
|
||||||
@ -334,18 +334,26 @@ public class QueryTest extends CubaTestCase {
|
|||||||
tx.commit();
|
tx.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Positional parameters are not supported
|
// Positional parameters
|
||||||
|
|
||||||
try (Transaction tx = persistence.createTransaction()) {
|
try (Transaction tx = persistence.createTransaction()) {
|
||||||
TypedQuery<User> query = persistence.getEntityManager().createQuery(
|
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));
|
query.setParameter(1, Arrays.asList(user1, user2, user3));
|
||||||
try {
|
List<User> list = query.getResultList();
|
||||||
query.getResultList();
|
assertEquals(3, list.size());
|
||||||
fail();
|
|
||||||
} catch (UnsupportedOperationException e) {
|
|
||||||
// ok
|
|
||||||
}
|
|
||||||
|
|
||||||
tx.commit();
|
tx.commit();
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
package com.haulmont.cuba.core.global;
|
package com.haulmont.cuba.core.global;
|
||||||
|
|
||||||
import com.haulmont.cuba.core.sys.jpql.DomainModel;
|
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.Entity;
|
||||||
import com.haulmont.cuba.core.sys.jpql.model.EntityBuilder;
|
import com.haulmont.cuba.core.sys.jpql.model.EntityBuilder;
|
||||||
import com.haulmont.cuba.core.sys.jpql.model.EntityImpl;
|
import com.haulmont.cuba.core.sys.jpql.model.EntityImpl;
|
||||||
@ -602,7 +602,7 @@ public class QueryTransformerAstBasedTest {
|
|||||||
new QueryTransformerAstBased(model,
|
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");
|
"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");
|
fail("Incorrectly placed 'having' passed");
|
||||||
} catch (ErrorsFoundException e) {
|
} catch (QueryErrorsFoundException e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -614,7 +614,7 @@ public class QueryTransformerAstBasedTest {
|
|||||||
new QueryTransformerAstBased(model,
|
new QueryTransformerAstBased(model,
|
||||||
"select h from sec$GroupHierarchy h join h.parent.constraints");
|
"select h from sec$GroupHierarchy h join h.parent.constraints");
|
||||||
fail("Not named join variable passed");
|
fail("Not named join variable passed");
|
||||||
} catch (ErrorsFoundException e) {
|
} catch (QueryErrorsFoundException e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,14 +108,14 @@ public class QueryTransformerSoftDeleteBugsTest extends TestCase {
|
|||||||
QueryTransformerRegex transformer = new QueryTransformerRegex(
|
QueryTransformerRegex transformer = new QueryTransformerRegex(
|
||||||
"select j from taxi$IndividualTelephone it, taxi$Job j\n" +
|
"select j from taxi$IndividualTelephone it, taxi$Job j\n" +
|
||||||
"where it.telephone like :phoneNumber and it.individual.id = j.caller.id\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");
|
transformer.addWhere("{E}.deleteTs is null");
|
||||||
String res = transformer.getResult();
|
String res = transformer.getResult();
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"select j from taxi$IndividualTelephone it, taxi$Job j\n" +
|
"select j from taxi$IndividualTelephone it, taxi$Job j\n" +
|
||||||
"where it.telephone like :phoneNumber and it.individual.id = j.caller.id\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);
|
res);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,13 +12,14 @@ import java.util.List;
|
|||||||
* @author chevelev
|
* @author chevelev
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
*/
|
*/
|
||||||
public class ErrorsFoundException extends RuntimeException{
|
public class QueryErrorsFoundException extends RuntimeException{
|
||||||
|
|
||||||
private List<ErrorRec> errorRecs;
|
private List<ErrorRec> errorRecs;
|
||||||
|
|
||||||
public ErrorsFoundException() {
|
public QueryErrorsFoundException() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ErrorsFoundException(String message, List<ErrorRec> errorRecs) {
|
public QueryErrorsFoundException(String message, List<ErrorRec> errorRecs) {
|
||||||
super(message);
|
super(message);
|
||||||
this.errorRecs = new ArrayList<>(errorRecs);
|
this.errorRecs = new ArrayList<>(errorRecs);
|
||||||
}
|
}
|
||||||
@ -28,11 +29,11 @@ public class ErrorsFoundException extends RuntimeException{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String getMessage() {
|
||||||
String result = "";
|
String message = super.getMessage();
|
||||||
for (ErrorRec rec : errorRecs) {
|
for (ErrorRec rec : errorRecs) {
|
||||||
result += rec + "\n";
|
message += "\n" + rec;
|
||||||
}
|
}
|
||||||
return result;
|
return message;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -69,7 +69,7 @@ public class QueryTransformerAstBased implements QueryTransformer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!errors.isEmpty()) {
|
if (!errors.isEmpty()) {
|
||||||
throw new ErrorsFoundException("Errors found", errors);
|
throw new QueryErrorsFoundException("Errors found", errors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,8 +150,6 @@ public class BulkEditorWindow extends AbstractWindow {
|
|||||||
datasource.setAllowCommit(false);
|
datasource.setAllowCommit(false);
|
||||||
|
|
||||||
createDataComponents();
|
createDataComponents();
|
||||||
|
|
||||||
datasource.refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void createDataComponents() {
|
protected void createDataComponents() {
|
||||||
@ -552,7 +550,7 @@ public class BulkEditorWindow extends AbstractWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected List<Entity> loadItems(View view) {
|
protected List<Entity> loadItems(View view) {
|
||||||
LoadContext lc = new LoadContext(metaClass);
|
LoadContext<Entity> lc = new LoadContext<>(metaClass);
|
||||||
lc.setSoftDeletion(false);
|
lc.setSoftDeletion(false);
|
||||||
|
|
||||||
List<UUID> ids = new ArrayList<>();
|
List<UUID> ids = new ArrayList<>();
|
||||||
|
@ -41,7 +41,7 @@ public class UserSetHelper {
|
|||||||
|
|
||||||
String listOfId = createIdsString(ids);
|
String listOfId = createIdsString(ids);
|
||||||
String randomName = RandomStringUtils.randomAlphabetic(10);
|
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");
|
Element param = condition.addElement("param");
|
||||||
param.addAttribute("name", "component$" + componentId + "." + randomName);
|
param.addAttribute("name", "component$" + componentId + "." + randomName);
|
||||||
|
Loading…
Reference in New Issue
Block a user