JPA Hibernate: как использовать привязку массива с CriteriaBuilder, т.Е. Сделать Окончательный запрос похожим «… в (?)», а не «… в (?, ?, ?)»?

#java #hibernate #jpa

Вопрос:

Я использую CriteriaBuilder из JPA для создания предложения long IN . Затем я обнаружил, что Oracle не поддерживает> 1000 элементов в предложении IN, поэтому мне нужно разделить это предложение на несколько, например in (?, ?, ?...) or in (?, ?, ?) .

Это сделано, но я думаю, что нам нужно оптимизировать больше, поскольку переменная длина списка параметров не может быть оптимизирована на стороне БД: из-за изменения длины оптимизатор Oracle будет считать, что каждый запрос — это отдельный запрос, поэтому план выполнения изменится. Но я думаю, что это в основном один или два запроса, поскольку это предложение IN возможно, но редко содержит> 1000 элементов. Итак, если я смогу привязать список к одной переменной, это будет 99% времени in (?) и 1% in (?) or in (?) , что очень хорошо для Oracle, чтобы увидеть сходство.

Я обнаружил, что в Hibernate есть setParameterList() подобное, и я думаю, что это то, что мне нужно. И я знаю, что могу unwrap() перевести JPA Query в режим гибернации Query , например:

 query.unwrap(org.hibernate.Query.class).getQueryString()
 

поэтому я хочу сделать то же самое, чтобы использовать метод setParameterList() . Но Hibernate жалуется на «не найден именованный параметр».

 org.hibernate.QueryParameterException: could not locate named parameter [excluded_orgIds0]
    at org.hibernate.engine.query.spi.ParameterMetadata.getNamedParameterDescriptor(ParameterMetadata.java:100)
    at org.hibernate.engine.query.spi.ParameterMetadata.getNamedParameterExpectedType(ParameterMetadata.java:106)
    at org.hibernate.internal.AbstractQueryImpl.determineType(AbstractQueryImpl.java:470)
    at org.hibernate.internal.AbstractQueryImpl.setParameterList(AbstractQueryImpl.java:839)
    ....
 

Что мне теперь делать?

РЕДАКТИРОВАТЬ: я обнаружил, что setParameterList() это уже вызывается в классе реализации, и он может сопоставить мой именованный параметр с параметром Hibernate positional, но похоже, что Hibernate наконец преобразует список в строку, поэтому привязка массива невозможна.

org.hibernate.ejb.QueryImpl.class :

     public TypedQuery<X> setParameter(String name, Object value) {
        try {
            if ( value instanceof Collection ) {
                query.setParameterList( name, (Collection) value );
            }
            else {
                query.setParameter( name, value );
            }
            registerParameterBinding( getParameter( name ), value );
            return this;
        }
        catch (QueryParameterException e) {
            throw new IllegalArgumentException( e );
        }
        catch (HibernateException he) {
            throw getEntityManager().convert( he );
        }
    }
 

Почему?


Одна из возможностей: весь SQL похож:

 select ih from ItemHistory as ih where ( ih.code=:param0 ) and ( ih.companyId in (select c.id from Company as c where ( ( c.organizationId in (:param1) ) or ( c.organizationId like :param2 ) or ( c.organizationId like :param3 ) ) and ( ( ( c.organizationId not in (:param4) ) and ( c.organizationId not in (:param5) ) ) and ( c.organizationId not like :param6 ) )) ) order by ih.eventDate desc
 

Когда я устанавливаю code или eventDate или not like ... , я не использую параметр, а просто вводю значения ( queryBuilder.eq(column, "333") ) . Я использую только queryBuilder.parameter(List.class, param1) там, где есть предложение IN .

Имеет ли позиционный параметр приоритет, чтобы, если я хочу использовать параметры, мне нужно было использовать их во всех местах?

Комментарии:

1. Вы не можете привязать список к одной переменной. Это не поддерживается JDBC и базой данных

2. Это также считается ответом, хорошо. Так или иначе, список будет преобразован в несколько параметров в строке, а для DB это будут разные запросы, поэтому оптимизатор не может включиться, верно? Эти структурно идентичные запросы, но с разным количеством параметров в предложении IN, будут проблемой для Oracle (и других DBs), верно?

3. Точно! Могу я спросить, почему у вас такое большое количество параметров IN?

4. Я не совсем понимаю, почему, поскольку они не поступают из БД. Я могу попытаться выяснить, почему, может быть, в понедельник.

5. Возможно, они из службы авторизации пользователя, другого микросервиса. Если это правда, у меня нет доступа к этой базе данных.