Принудительно Hibernate всегда использовать конструктор по умолчанию без аргументов, даже если указаны параметры выбора - PullRequest
0 голосов
/ 15 октября 2019

Сначала немного контекста - я реализую API, в котором запросы содержат поля, которые интересуют клиента, в основном параметры для непосредственного выбора. Поскольку общий размер данных достаточно велик, если его не ограничивать таким образом, это делает очевидным выигрыш в производительности, когда речь идет о сериализации и передаче данных, а также ограничении объема данных, извлекаемых из базы данных. Поэтому я пытаюсь передать их для выбора при выполнении запроса к базе данных.

Проблема, с которой я сталкиваюсь, заключается в том, что при выполнении запроса с помощью выбора Hibernate ожидает существование определенного конструктора, который соответствует параметрам выбора. Например, если я укажу, что меня интересуют только столбцы id (long) и model (String) в моем классе BasicInfo, то Hibternate попытается найти и вызвать конструктор BasicInfo(int, String). На это указывает сообщение об ошибке:

org.hibernate.hql.internal.ast.QuerySyntaxException: Невозможно найти соответствующий конструктор в классе [my.package.BasicInfo]. Ожидаемые аргументы: long, java.lang.String [выберите новый my.package.BasicInfo (агентAlias0.id, генерируетсяAlias0.model) из my.package.BasicInfo asагентAlias0]

Это невариант для меня. Клиент может пожелать запросить, скажем, model (String) и serial (также String) в одном запросе в этом порядке, тогда как другой клиент может пожелать запросить те же поля в обратном порядке. Поскольку я смогу создать только одну комбинацию конструктора BasicInfo(String, String), один из запросов будет получать данные в обратном порядке. Даже без учета этого факта мне пришлось бы создавать все возможные перестановки конструкторов всех возможных полей, которые могут быть запрошены, что - с учетом количества полей, существующих в этом классе - делает его очень неэффективным, если не невозможным, делом.

Мне нужен способ заставить Hibernate использовать конструктор класса по умолчанию, даже если указан параметр запроса select, и использовать установщики для установки запрошенных полей. Если нет, то, возможно, другой способ, который позволил бы мне не извлекать полные строки данных из базы данных при каждом запросе (и затем ограничивать их в коде приложения перед отправкой обратно клиенту).

IМы также пытались зарегистрировать пользовательский перехватчик Hibernate и переопределяли его метод instantiate следующим образом:

public class CustomInterceptor extends EmptyInterceptor {

    @Override
    public Object instantiate(String entityName, EntityMode entityMode, Serializable id) {
        if(entityName.equals(BasicInfo.class.getName()))
            return new BasicInfo();
        return null;
    }

}

, надеясь, что это изменит стратегию создания объекта. В этом случае, когда я не указываю параметры выбора, этот метод вызывается правильно. Однако, когда заданы параметры выбора, он не вызывается вообще, и Hibternate пытается напрямую вызвать конструктор с конкретными аргументами.

Ниже приведены соответствующие части проекта:

Настройка кода выбора параметров (несущественные части кода удалены для ясности):

CriteriaQuery<T> query = cb.createQuery(responseClass);
Root<T> from = query.from(responseClass);
// Handle select
CriteriaQuery<T> select = null;
if(request.getSelect() != null) {
    List<Selection<?>> selectionList = new ArrayList<Selection<?>>();
    for(String s : request.getSelect()) {
        selectionList.add(from.get(s));
    }
    select = query.multiselect(selectionList);
} else {
    // select all fields
    select = query.select(from);
}
TypedQuery<T> typedQuery = em.createQuery(select);      
List<T> itemsList = typedQuery.getResultList();

И applicaion.yml:

spring:
  datasource:
    platform: h2
    driver-class-name: org.h2.Driver
    url: jdbc:h2:mem:db;DB_CLOSE_DELAY=-1
  jpa:
    hibernate:
      ddl-auto: create-drop
    show-sql: true

1 Ответ

0 голосов
/ 15 октября 2019

Я использую старый интерфейс и получаю набор результатов как List<Object[]>, просто используя setProjection(myProjectionList). Object[] - это не то, что вам нужно, но преобразование его в Map<String, Object> является однострочным, и после преобразования в JSON вы можете увидеть то же самое, что и с вашим неполным объектом.

Не уверен, если онработает в вашем случае, и применимо ли это к JPA2 или к тому, что вы используете.

Если вы настаиваете на объектах, вы можете создать их самостоятельно, возможно, скопировав поле в «правильные» позиции и затем вызвав new BasicInfo(myRearangedArray) где конструктор находит каждого члена в фиксированной позиции. AFAIK это то, что делает hibernate, когда он получает полную сущность, так что вы можете использовать его код и сэкономить на написании конструктора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...