Нетерпеливая выборка коллекций в Hibernate с помощью ScrollableResults

Я пытаюсь использовать Hibernate для извлечения примерно 100 миллионов строк из таблицы. У меня есть постоянный элемент объекта, который содержит набор комиссий внутри (другой постоянный объект). Учитывая, что я буду перебирать результат и получать доступ к сборам для каждого объекта, я хочу с нетерпением получать сборы, чтобы избежать проблемы n+1.

Я также должен упомянуть, что я хочу присоединить его к другой таблице с именем Provider (отображение один к одному, но без внешнего ключа). Я пытался:

String query = "select new " + Order.class.getName() 
           + "(i, p) from Item i left join fetch i.fees f, Provider p where "
           + "p.factoryId=i.factoryId and p.factoryRef=i.factoryRef";

return session.createQuery(query).scroll();

Класс My Order содержит поле Provider и поле Item. Я получаю эту ошибку:

Вызвано: org.hibernate.QueryException: в запросе указана выборка объединения, но владелец извлеченной ассоциации не присутствует в списке выбора

Я хотел бы получить прокручиваемый список Order, который содержит Item (с нетерпеливо полученными сборами) и Provider.


person Mariano Martes    schedule 18.04.2012    source источник


Ответы (2)


Этот код от SelectClause вызывает у вас проблемы:

if ( !fromElementsForLoad.contains( origin ) ) {
                        throw new QueryException(
                                "query specified join fetching, but the owner " +
                                "of the fetched association was not present in the select list " +
                                "[" + fromElement.getDisplayText() + "]"
                        );

Как видите, когда упоминается ключевое слово fetch, hibernate проверяет, запрашивали ли вы родительское поле fetch. fromElementsForLoad.contains( origin )

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

Я полагаю, что в вашем случае - обертывание Item.class в новый Order.class скрывает тот факт, что вы используете родительское поле выборки в запросе.

На данный момент у меня нет возможностей отладки, поэтому я не могу это проверить. попробуйте отладить именно эту строку из SelectClause.class и посмотреть, какие элементы содержит коллекция fromElementsForLoad.

Если вы хотите избежать проблемы n+1, я бы рекомендовал инициализировать Order.class после запроса. Вы можете выбрать только Item и Provider.

Если вы не можете подтвердить это, на следующей неделе я доберусь до нужного компьютера и дополню свой ответ.

person R-E-L    schedule 11.08.2012
comment
Я думаю, что этот ответ правильный. Если это так, вы должны иметь возможность сообщить Hibernate, что вы на самом деле извлекаете Item, изменив запрос, чтобы он возвращал List, а не строил Order: select i, p from .... Затем вам придется создать Orders вручную. - person Tom Anderson; 11.08.2012

Попробуйте удалить left join fetch i.fees f и выполните активную выборку в отображении.

person Avihai Marchiano    schedule 11.08.2012