Список передачи 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. Ссылка 1
  2. Ссылка 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"
)