Подтвердить что ты не робот

Размер сбора счетчика Hibernate без инициализации

Есть ли способ подсчитать размер связанной коллекции без инициализации?

например.

Select count(p.children) from Parent p

(есть веская причина, почему я не могу сделать это каким-либо другим способом, так как предложение where, где предложение более сложное, а my from - полиморфный запрос)

Спасибо.

4b9b3361

Ответ 1

Возможным решением, отличным от запросов, может быть сопоставление children с lazy="extra" (в нотации XML). Таким образом, вы можете выбрать родителя с любым запросом, который вам нужен, а затем вызвать parent.getChildren().size() без загрузки всей коллекции (выполняется только запрос типа SELECT COUNT).

С аннотациями это будет

@OneToMany
@org.hibernate.annotations.LazyCollection(
org.hibernate.annotations.LazyCollectionOption.EXTRA
)
private Set<Child> children = new HashSet<Child>();

Обновление: Цитата из Java Persistence with Hibernate, ch. 13.1.3:

Прокси инициализируется, если вы вызываете любой метод, который не является идентификатором getter метод, сбор инициализируется, если вы начинаете итерирование через свои элементы или если вы вызываете любые операции управления коллекцией, такие как size() и contains(). Hibernate предоставляет дополнительную настройку, которая в основном полезна для больших коллекций; они могут отображаться как лишние. [...]

[Отображается как указано выше], коллекция больше не инициализируется, если вы вызываете size(), contains() или isEmpty() - запрашивается база данных для получения необходимой информации. Если его a Map или List, операции containsKey()и get() также напрямую запрашивают базу данных.

Итак, с сущностью, отображаемой как указано выше, вы можете сделать

Parent p = // execute query to load desired parent
// due to lazy loading, at this point p.children is a proxy object
int count = p.getChildren().size(); // the collection is not loaded, only its size

Ответ 2

Вы можете использовать Session # createFilter, который является формой HQL, которая явно работает с коллекциями. Например, вы указываете родителя и детей, поэтому, если у вас есть Person p, самая простая форма:

session.createFilter( p.getChildren(), "" ).list()

Это просто возвращает вам список детей. Важно отметить, что возвращенная коллекция не "живая", она никоим образом не связана с p.

Интересная часть исходит из второго аргумента. Это фрагмент HQL. Здесь, например, вы можете:

session.createFilter( p.getChildren(), "select count(*)" ).uniqueResult();

Вы упомянули, что у вас есть предложение where, поэтому вы также можете захотеть:

session.createFilter( p.getChildren(), "select count(*) where this.age > 18" ).uniqueResult();

Обратите внимание, что из предложения нет. То есть, из предложения подразумевается предложение from. Элементам коллекции присваивается псевдоним 'this', поэтому вы можете ссылаться на него из других частей фрагмента HQL.

Ответ 3

Вы можете сделать то же самое:

@Override
public FaqQuestions getFaqQuestionById(Long questionId) {
    session = sessionFactory.openSession();
    tx = session.beginTransaction();
    FaqQuestions faqQuestions = null;
    try {
        faqQuestions = (FaqQuestions) session.get(FaqQuestions.class,
                questionId);
        Hibernate.initialize(faqQuestions.getFaqAnswers());

        tx.commit();
        faqQuestions.getFaqAnswers().size();
    } finally {
        session.close();
    }
    return faqQuestions;
}

Просто используйте faqQuestions.getFaqAnswers(). size() в вашем контроллере, и вы получите размер, если лениво проинсталлирован список, не получая сам список.