Страницы

Поиск по вопросам

вторник, 13 ноября 2018 г.

Hibernate many to many бесконечно вложенный json

Есть три таблицы user, group, user2group. Связь много ко многим.
Если прописать мапинг только в классе User, то контроллер выдает json который и нужен.
@ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "user2group", joinColumns = { @JoinColumn(name = "user_id") }, inverseJoinColumns = { @JoinColumn(name = "group_id") }) private Set groups = new HashSet();
Но если мапим связанные данные в классе Group, то при попытке получить список групп с привязанными к ним клиентами, контроллер начинает выдавать json, но при этом бесконечно проваливается в связанные сущности.
Мапинг для класса Group сейчас у меня следующий:
@ManyToMany(mappedBy = "groups") private Set users = new HashSet();
Записи я получаю следующим образом
Session session = sessionFactory.getCurrentSession(); Query query = session.createQuery("FROM User"); List users = query.list();
Также, на случай если это важно. По началу при обращении к соответствующему урлу, вылетало исключение, которое починилось установкой следующего нагугленного свойства при инициализации бина LocalSessionFactory
properties.put("hibernate.enable_lazy_load_no_trans", true);
Вопрос. Чтобы получать json единой вложенности, нужны какие-то особенные настройки хибернейта? Или прописывать особый маппинг?
В ходе гугления вопроса мне начало казаться, что особо ни у кого не возникает подобной сложности, может тут подход нужен иной?
Задача Возможность получить всех юзеров, где к каждому юзеру будет прикреплен список групп, в которых он числится. Пример:
[ {id:1, name:"user1", groups:[{id:1, title:"group1"}, {id:5, title:"group5"}]}, {id:2, name:"user2", groups:[]}, {id:3, name:"user3", groups:[{id:3, title:"group3"}]}, ]
Возможность получить все группы, где к каждой группе будет прикреплен список юзеров, которые числятся в этой группе Пример:
[ {id:1, title:"group1", users:[{id:1, name:"user1"}, {id:5, name:"user5"}]}, {id:2, title:"group2", users:[]}, {id:3, title:"group3", users:[{id:3, name:"user3"}]}, ]


Ответ

Не очень хорошая практика - отдавать ваши ORM-сущности непосредственно наружу.
Во-первых, вы смешиваете разные задачи в одном классе.
Во-вторых, вы отдаете наружу все его состояние, которое, возможно, не стоит отдавать.
В третьих, когда-нибудь вам потребуется отдавать для разных задач разный набор полей.
Обычно, эта проблема решается паттерном DTO (Data Transfer Object).
Вы просто создаете классы UserDto и GroupDto, которые содержат только необходимые поля, геттеры-сеттеры, конструктор по-умолчанию и JSON-аннотации. При отдаче наружу в слое представления (контроллере) перекладываете поля из ORM-объектов в DTO-объекты. Можно это делать как вручную (завести static-метод в DTO), так и использовать какой-нибудь маппер вроде Dozer.
Для получения групп с вложенными в нее пользователями, нужно завести отдельную DTO, например, как GroupWithUsersDto в примере ниже.

public class GroupDto { @JsonProperty("id") private Long id; @JsonProperty("title") private String title;
// сеттеры-геттеры
public static GroupDto fromModel(Group group) { GroupDto dto = new GroupDto(); dto.setId(group.getId()); dto.setTitle(group.getTitle()); return dto; }
public class UserDto { @JsonProperty("id") private Long id; @JsonProperty("name") private String name;
// сеттеры-геттеры
public static UserWithGroupsDto fromModel(User user) { UserWithGroupsDto dto = new UserWithGroupsDto(); dto.setId(user.getId()); dto.setName(user.getName()); return dto; } }
Для выдачи пользователей с их группами:
public class UserWithGroupsDto { @JsonProperty("id") private Long id; @JsonProperty("name") private String name; @JsonProperty("groups") private List groups;
// сеттеры-геттеры
public static UserWithGroupsDto fromModel(User user) { UserWithGroupsDto dto = new UserWithGroupsDto(); dto.setId(user.getId()); dto.setName(user.getName()); List groupDtos = new ArrayList<>();
for (Group group : user.getGroups()) { groupDtos.add(GroupDto.fromModel(group)); } dto.setGroups(groupDtos);
return dto; } }

Для выдачи групп с пользователями:
public class GroupWithUsersDto{ @JsonProperty("id") private Long id; @JsonProperty("title") private String title; @JsonProperty("users") private List
// сеттеры-геттеры
public static GroupWithUsersDto fromModel(Group group) { GroupWithUsersDto dto = new GroupWithUsersDto(); dto.setId(group.getId()); dto.setTitle(group.getTitle()); List usersDtos = new ArrayList<>();
for (User user : group.getUsers()) { usersDtos.add(UserDto.fromModel(user)); } dto.setUsers(usersDtos); return dto; }

Комментариев нет:

Отправить комментарий