Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Java [игнор отключен] [закрыт для гостей] / Hibernate несколько HQL для заполнения сущности / 18 сообщений из 18, страница 1 из 1
24.09.2013, 16:16:20
    #38406285
SkyFire
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Hibernate несколько HQL для заполнения сущности
Добрый день, вопрос следующий.
Имеется 3 сущности, например "от балды" : Юзер , у него много Постов и у него много Категорий . Т.е. отношения Юзера один ко многим (к таблице постов и таблице категорий). Упрощённо

Код: java
1.
2.
3.
4.
5.
Class User {
    private List<Post> posts;
    private List<Category> categories;
    //другие свойства юзера(имя, логин и т д)
}

Аннотации отношений я опустил, но имеем ввиду что загрузка Lazy.
Вопрос: Как выбрать всех юзеров с уже заполнеными коллекциями posts и categories , при этом чтобы Hibernate выполнили всего 2 запроса, в первом выбрал всех юзеров с джоином постов, во втором всех юзеров с джоином категорий.

Пока получилось сделать только так:
Код: java
1.
2.
3.
4.
public List<User> findAll() {
        return session.getCurrentSession()
                .createQuery("from User u left join fetch u.posts").list();
    }


Но в этом случае при дальнейшем обращении к категориям будет иметь на каждого юзера по дополнительному запросу в БД (через LAZY загрузку), что не есть хорошо (юзеров много).

Теоретически нужно как-то выполнить 2 запроса в методе findAll():
Код: java
1.
2.
createQuery("from User u left join fetch u.posts")
createQuery("from User u left join fetch u.categories")


Но я, к сожалению, не знаю как.
...
Рейтинг: 0 / 0
24.09.2013, 16:21:12
    #38406291
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Hibernate несколько HQL для заполнения сущности
Так?
from User u
left join fetch u.posts
left join fetch u.categories
...
Рейтинг: 0 / 0
24.09.2013, 16:23:51
    #38406295
SkyFire
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Hibernate несколько HQL для заполнения сущности
org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
...
Рейтинг: 0 / 0
24.09.2013, 16:26:42
    #38406297
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Hibernate несколько HQL для заполнения сущности
SkyFireorg.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
Есть такое. Bag это не упорядоченая коллекция в хибернейт. Дело в том, что когда запускается join на несколько коллекций, то хибер не может из результатов запроса понять где какой user.id, чтобы правильно распихать результат по коллекциям.
Один из вариантов решения это замена Bag, на упорядоченый List. Для этого нужно в маппинге указать, как именно упорядочена коллекций.
...
Рейтинг: 0 / 0
24.09.2013, 16:27:34
    #38406299
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Hibernate несколько HQL для заполнения сущности
http://stackoverflow.com/questions/13334831/multiplebagfetchexception-thrown One way to do this is by specifying the Hibernate specific @IndexColumn or the JPA standard @OrderColumn on the relations.
...
Рейтинг: 0 / 0
24.09.2013, 16:44:49
    #38406323
SkyFire
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Hibernate несколько HQL для заполнения сущности
Blazkowicz,

Вот с этим @OrderColumn у меня и проблема.
Класс User является "владельцем" связи с категориями, т.е.

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
Class User {

@Id
@Column(name = "id")
private String id;
    
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
@OrderColumn(name="user_id")
private List<Category> categories = new ArrayList<Category>();

...
}


класс Category ничего не знает о User.

При добавлении аннотации @OrderColumn(name="user_id") ловим следующее:
...hibernate.MappingException: Repeated column in mapping for collection: ru.example.unity.model.User.categories column: user_id

Возможно я вообще не правильно все понял. Поправьте пожалуйста.
...
Рейтинг: 0 / 0
24.09.2013, 16:49:14
    #38406330
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Hibernate несколько HQL для заполнения сущности
Давайте с моделью сначала разберемся.
То что категория ничего не знает о юзере - это мне понятно. Это логично.
Откуда вот только тогда у категории user_id - этого я не понимаю. Т.е. должно быть many-to-many.
И следующее. У всех категорий одного юзера - все user_id одинаковые. Поэтому сортировка по ним бессмысленна.
...
Рейтинг: 0 / 0
24.09.2013, 16:58:53
    #38406353
SkyFire
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Hibernate несколько HQL для заполнения сущности
Да, пример с категориями не очень удачный и больше подходит для многие ко многим.
В действительности я "проецирую" этот упрощённый пример на свой реальный. Давайте условимся что "Юзеры" действительно относится к "Категориям" как многие к одному. Т.е.

Categories
iduser_idname12Авто22Вело33Вело44Спорт54Авто
...
Рейтинг: 0 / 0
24.09.2013, 17:00:00
    #38406356
SkyFire
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Hibernate несколько HQL для заполнения сущности
SkyFire"Юзеры" действительно относится к "Категориям" как многие к одному.
Точнее один ко многим конечно.
...
Рейтинг: 0 / 0
24.09.2013, 17:01:06
    #38406358
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Hibernate несколько HQL для заполнения сущности
Логично попробовать
@OrderColumn(name="id")
...
Рейтинг: 0 / 0
24.09.2013, 17:16:31
    #38406382
SkyFire
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Hibernate несколько HQL для заполнения сущности
Теперь запрос строится верно (т.е. 2 лефт джоина обоих таблиц), но спустя 5 секунд:


17:09:40,244 WARN [org.hibernate.engine.loading.internal.LoadContexts] (http--127.0.0.1-8080-1) HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@4f96de53<;rs=org.postgresql.jdbc4.Jdbc4ResultSet@68577956>;
17:09:40,247 WARN [org.hibernate.engine.loading.internal.CollectionLoadContext] (http--127.0.0.1-8080-1) HHH000160: On CollectionLoadContext#cleanup, localLoadingCollectionKeys contained [100] entries
17:09:40,250 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/main].[unity-synch]] (http--127.0.0.1-8080-1) Servlet.service() for servlet unity-synch threw exception: java.lang.OutOfMemoryError: Java heap space

Сам SQL возвращает порядка 200 строк, теперь я в полном "ступоре" :(
...
Рейтинг: 0 / 0
24.09.2013, 17:22:58
    #38406392
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Hibernate несколько HQL для заполнения сущности
...
Рейтинг: 0 / 0
25.09.2013, 10:14:48
    #38406856
пролетевший
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Hibernate несколько HQL для заполнения сущности
Blazkowiczfrom User u
left join fetch u.posts
left join fetch u.categories
Здесь засада на уровне SQL. такой запрос возвращает строки для каждого поста со всеми категориями ( картезианское произведение ). 100 постов и 100 категорий это уже 10000 строк. Потом хибер пытается их собрать вместе удаляя лишнее, поэтому и ругался на Bag.
Больше 2х таблиц в join пихать надо с большой осторожностью.
Лучше грузить lazy с Batch Fetch .
Оффтоп, недавно настраивали производительность в приложении и обнаружили что MS SQL Join для небольшой выборки делает в несколько раз медленнее, чем 2 отдельных запроса. основная база около 10 млн записей, на каждую в среднем 20 записей в дочерних таблицах. Для обработки выбираются 4 записи из основной таблицы, ц дочерними коллекциями. Удаление любовно составленных join fetch улучшило среднюю производительность в 5 раз.
...
Рейтинг: 0 / 0
25.09.2013, 10:29:34
    #38406879
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Hibernate несколько HQL для заполнения сущности
пролетевший Здесь засада на уровне SQL. такой запрос возвращает строки для каждого поста со всеми категориями ( картезианское произведение ). 100 постов и 100 категорий это уже 10000 строк.
По-моему модель, в котором коллекции зачастую имеют десятки элементов и более это уже как минимум странно. Возможно даже глупо. Это всё равно что в отношении "Автомобиль - Район Регистрации" в "Районе" завести коллекцию "Автомобилей".

пролетевший
Потом хибер пытается их собрать вместе удаляя лишнее, поэтому и ругался на Bag.

На Bag он ругался не из-за количества, а из-за того что в неупорядоченых списках он не может правильно найти нужные FK из результата запроса.

пролетевший
Больше 2х таблиц в join пихать надо с большой осторожностью.

Хотелось бы уточнить: больше двух джоинов для ассоциаций one-to-many.

пролетевший
Лучше грузить lazy с Batch Fetch .
Оффтоп, недавно настраивали производительность в приложении и обнаружили что MS SQL Join для небольшой выборки делает в несколько раз медленнее, чем 2 отдельных запроса. основная база около 10 млн записей, на каждую в среднем 20 записей в дочерних таблицах. Для обработки выбираются 4 записи из основной таблицы, ц дочерними коллекциями. Удаление любовно составленных join fetch улучшило среднюю производительность в 5 раз.
Всё верно. Спасибо за коментарий. Я сразу про это как-то не вспомнил.
...
Рейтинг: 0 / 0
25.09.2013, 11:12:31
    #38406949
SkyFire
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Hibernate несколько HQL для заполнения сущности
BlazkowiczПо-моему модель, в котором коллекции зачастую имеют десятки элементов и более это уже как минимум странно. Возможно даже глупо.
Спорный вопрос как мне кажется, сущности бывают разные.
А по теме, с @OrderColumn так ничего и не вышло, к сожалению разбираться в чём проблема времени совсем нет. Проблема решилась заменой List<Category> на Set<Category>.
Огромное спасибо всем за помощь.
...
Рейтинг: 0 / 0
25.09.2013, 11:20:45
    #38406965
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Hibernate несколько HQL для заполнения сущности
SkyFireСпорный вопрос как мне кажется, сущности бывают разные.

Ну, давайте поспорим. В реальной жизни у юзера может быть сколько угодно постов. Т.е. у вас User.posts безразмерный список!
Делать join на эту коллекцию это за гранью разумного.
Даже lazy делать нужно с предельной осторожностью, потому что не факт что постраничная загрузка данных в этой коллекции будет работать. В противном случае мы отхватываем баги, когда неожиданно сервер будет уходить в OOME случайно загрузив User.posts.


SkyFireА по теме, с @OrderColumn так ничего и не вышло, к сожалению разбираться в чём проблема времени совсем нет. Проблема решилась заменой List<Category> на Set<Category>.

Да. Точно. Это второй рецепт, про который я успешно забыл.
...
Рейтинг: 0 / 0
25.09.2013, 11:52:55
    #38407017
SkyFire
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Hibernate несколько HQL для заполнения сущности
Хорошо, вы меня переубедили :) У меня слишком мало опыта маппинге на дом-объекты да и в Java в целом.
...
Рейтинг: 0 / 0
27.09.2013, 13:53:47
    #38409821
Atum1
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Hibernate несколько HQL для заполнения сущности
А Если написать нативный sql ?
и class RawMapper по аналогии с Jdbc подходом?!

или Вы хотите именно HQL освоить ?
...
Рейтинг: 0 / 0
Форумы / Java [игнор отключен] [закрыт для гостей] / Hibernate несколько HQL для заполнения сущности / 18 сообщений из 18, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]