Всегда ли Hibernate использует загрузку при поиске по некоторым дочерним свойствам? - PullRequest
1 голос
/ 06 марта 2012

Можете ли вы помочь мне решить эту проблему.У меня есть 2 класса.Один - Устройство, второй - Предупреждение, сгенерированное устройством.Класс устройства выглядит следующим образом.

public class Device
{
    private Long deviceId;  
    private String deviceName;
    @OneToMany
    private List<Alert> alerts;
}

public class Alert
{
    private Long deviceId;  
    private String alertText;
    private String alertType;
    private Date alertTime;
}

тогда я хочу, чтобы все устройства генерировали оповещения.Для этого я использую Criteria.API

Criteria crit= session.createCriteria(Device.class);
Criteria alertCriteria=crit.createCreateria("alerts");
alertCriteria.add(Resrictions.between("alertTime", startDate, endDate));

crit.setResultTransformer(DistinctRootEntityResultTransformer.INSTANCE);

Проблема с этим подходом, при котором сгенерированный SQL-запрос извлекает все оповещения с последующим применением преобразователя результатов.это выглядит примерно так

select deviceID,deviceName,alertText,alertType,alertTime from devices d, alerts a left join  a.deviceID=d.deviceID;

Этот запрос неэффективен.В случае, если таблица оповещений огромна, это занимает несколько минут.Поэтому у меня есть несколько вопросов:

  • будет ли добавление alertCriteria.add(Resrictions.between("alertTime"),startDate,endDate); всегда приводить к получению предупреждений в один выбор?Как этого избежать?
  • Как я могу получить все различные устройства, имеющие оповещения, без использования ResultTransformer?

После реализации второго примера я получаю NPE в коде гибернации: java.lang.NullPointerException в org.hibernate.loader.criteria.CriteriaQueryTranslator.getProjectedTypes (CriteriaQueryTranslator.java:362) в org.hibernate.criterion.SubqueryExpression.createAndSetInnerQueryhjSubqueryExpression.java:69) по адресу org.hibernate.loader.criteria.CriteriaQueryTranslator.getWhereCondition (CriteriaQueryTranslator.java:380) по адресу org.hibernate.loader.criteria.CriteriaJoinWalker.критерии.CriteriaJoinWalker. (CriteriaJoinWalker.java:82) в org.hibernate.loader.criteria.CriteriaLoader. (CriteriaLoader.java:92) в org.hibernate.impl.SessionImpl.list (SessionImpl.java:16h) или.impl.CriteriaImpl.list (CriteriaImpl.java:347)

1 Ответ

0 голосов
/ 07 марта 2012

ответ 1: при фильтрации по дочерним свойствам sql должен присоединиться к дочерней таблице, чтобы получить связанные корневые объекты

ответ 2: если вам нужны устройства, у которых есть какие-либо предупреждения в заданном диапазоне

List<Device> devicesWithAlerts = session.createCriteria(Device.class, "device")
    .createCriteria("alerts")
        .add(Resrictions.between("alertTime", startDate, endDate))
    .setResultTransformer(DistinctRootEntityResultTransformer.INSTANCE)
    .List<Device>();

// or more efficiently because only wanted entities are loaded

List<Device> devicesWithAlerts = session.createCriteria(Device.class, "device")
    .Add(Subqueries.PropertyIn("id", DetachedCriteria.For(Device.class)
        .CreateCriteria("alerts")
            .add(Resrictions.between("alertTime", startDate, endDate))
        .SetProjection(Projections.Distinct(Projections.Id()))
        ))
    .List<Device>();
...