Список передачи JPA в предложение IN в именованном собственном запросе
Я знаю, что могу передать список именованному запросу в JPA, но как насчет NamedNativeQuery? Я пробовал много способов, но все же не могу просто передать список в NamedNativeQuery. Кто-нибудь знает, как передать список в подразделение in в NamedNativeQuery? Большое вам спасибо!
NamedNativeQuery выглядит следующим образом:
@NamedNativeQuery(
name="User.findByUserIdList",
query="select u.user_id, u.dob, u.name, u.sex, u.address from user u "+
"where u.user_id in (?userIdList)"
)
и он называется так:
List<Object[]> userList = em.createNamedQuery("User.findByUserIdList").setParameter("userIdList", list).getResultList();
Однако результат не такой, как я ожидал.
System.out.println(userList.size()); //output 1
Object[] user = userList.get(0);
System.out.println(user.length); //expected 5 but result is 3
System.out.println(user[0]); //output MDAVERSION which is not a user_id
System.out.println(user[1]); //output 5
System.out.println(user[2]); //output 7
Ответы
Ответ 1
Список не является допустимым параметром для собственного SQL-запроса, поскольку он не может быть связан в JDBC. У вас должен быть параметр для каждого аргумента в списке.
где u.user_id в (? id1,? id2)
Это поддерживается через JPQL, но не SQL, поэтому вы можете использовать JPQL вместо собственного запроса.
Некоторые поставщики JPA могут поддерживать это, поэтому вам может понадобиться зарегистрировать ошибку у вашего провайдера.
Ответ 2
Вышеупомянутый принятый ответ не верен и вывел меня из колеи на многие дни !!
JPA и Hibernate принимают коллекции в собственном запросе с использованием Query.
Вам просто нужно сделать
String nativeQuery = "Select * from A where name in :names"; //use (:names) for older versions of hibernate
Query q = em.createNativeQuery(nativeQuery);
q.setParameter("names", l);
Также см. ответы здесь, которые предлагают то же самое (я выбрал приведенный выше пример из одного из них)
- Ссылка 1
- Ссылка 2, в которой упоминается, в каких случаях работает парантез, и который дает список в качестве параметра
Ответ 3
В зависимости от вашей базы данных/поставщика/драйвера/и т.д. вы можете фактически передать список в качестве связанного параметра в собственный запрос JPA.
Например, при использовании Postgres и EclipseLink выполняется следующее (возвращает true), демонстрируя многомерные массивы и как получить массив двойной точности. (Do SELECT pg_type.* FROM pg_catalog.pg_type
для других типов, возможно, те, у которых _
, но отключите его, прежде чем использовать его.)
Array test = entityManager.unwrap(Connection.class).createArrayOf("float8", new Double[][] { { 1.0, 2.5 }, { 4.1, 5.0 } });
Object result = entityManager.createNativeQuery("SELECT ARRAY[[CAST(1.0 as double precision), 2.5],[4.1, 5.0]] = ?").setParameter(1, test).getSingleResult();
Приведение происходит таким образом, чтобы литеральный массив был двойным, а не числовым.
Больше, чем вопрос - я не знаю, как или вы можете выполнять именованные запросы; Я думаю, это зависит, может быть. Но я думаю, что следующее будет работать для массива.
Array list = entityManager.unwrap(Connection.class).createArrayOf("int8", arrayOfUserIds);
List<Object[]> userList = entityManager.createNativeQuery("select u.* from user u "+
"where u.user_id = ANY(?)")
.setParameter(1, list)
.getResultList();
У меня нет той же схемы, что и OP, поэтому я не проверял это точно, но я думаю, что она должна работать - опять же, по крайней мере, в Postgres и EclipseLink.
Кроме того, ключ был найден в: http://tonaconsulting.com/postgres-and-multi-dimensions-arrays-in-jdbc/
Ответ 4
Пробовал в JPA2 с Hibernate как провайдером, и кажется, что hibernate поддерживает получение списка для "IN", и он работает. (По крайней мере, для названных запросов, и я считаю, что это будет похоже на именованные запросы NATIVE)
Что внутри hibernate генерирует динамические параметры внутри IN так же, как количество элементов в переданном списке.
Итак, в примере выше
List<Object[]> userList = em.createNamedQuery("User.findByUserIdList").setParameter("userIdList", list).getResultList();
Если список содержит 2 элемента, запрос будет выглядеть как
select u.user_id, u.dob, u.name, u.sex, u.address from user u "+
"where u.user_id in (?, ?)
и если он имеет 3 элемента, он выглядит как
select u.user_id, u.dob, u.name, u.sex, u.address from user u "+
"where u.user_id in (?, ?, ?)
Ответ 5
Используя спящий режим, JPA 2.1 и данные deltaspike, я мог бы передать список в качестве параметра в запросе, содержащем предложение IN. мой запрос ниже.
@Query(value = "SELECT DISTINCT r.* FROM EVENT AS r JOIN EVENT AS t on r.COR_UUID = t.COR_UUID where " +
"r.eventType='Creation' and t.eventType = 'Reception' and r.EVENT_UUID in ?1", isNative = true)
public List<EventT> findDeliveredCreatedEvents(List<String> eventIds);
Ответ 6
в настоящее время я использую JPA 2.1 с Hibernate
Я также использую условие IN с собственным запросом. Пример моего запроса
SELECT ... WHERE table_name.id IN (?1)
Я заметил, что невозможно передать строку типа "id_1, id_2, id_3" из-за ограничений, описанных Джеймсом
Но когда вы используете jpa 2.1 + hibernate, можно передать список строковых значений. Для моего случая следующий код действителен:
List<String> idList = new ArrayList<>();
idList.add("344710");
idList.add("574477");
idList.add("508290");
query.setParameter(1, idList);
Ответ 7
В моем случае (EclipseLink, PostGreSQL) это работает:
ServerSession serverSession = this.entityManager.unwrap(ServerSession.class);
Accessor accessor = serverSession.getAccessor();
accessor.reestablishConnection(serverSession);
BigDecimal result;
try {
Array jiraIssues = accessor.getConnection().createArrayOf("numeric", mandayWorkLogQueryModel.getJiraIssues().toArray());
Query nativeQuery = this.entityManager.createNativeQuery(projectMandayWorkLogQueryProvider.provide(mandayWorkLogQueryModel));
nativeQuery.setParameter(1,mandayWorkLogQueryModel.getPsymbol());
nativeQuery.setParameter(2,jiraIssues);
nativeQuery.setParameter(3,mandayWorkLogQueryModel.getFrom());
nativeQuery.setParameter(4,mandayWorkLogQueryModel.getTo());
result = (BigDecimal) nativeQuery.getSingleResult();
} catch (Exception e) {
throw new DataAccessException(e);
}
return result;
Также в запросе нельзя использовать IN (?), потому что вы получите ошибку вроде:
Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: numeric = numeric[]
"IN (?)" Должен быть заменен на "= ЛЮБОЙ (?)"
Мое решение было основано на концепции Erhannis.
Ответ 8
Вы можете попробовать этот : userIdList вместо (? userIdList)
@NamedNativeQuery(
name="User.findByUserIdList",
query="select u.user_id, u.dob, u.name, u.sex, u.address from user u "+
"where u.user_id in :userIdList"
)