#java #hibernate #spring_mvc
Есть три таблицы 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"}]},
]
Ответы
Ответ 1
Не очень хорошая практика - отдавать ваши 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 Listgroups; // сеттеры-геттеры 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; } Ответ 2
Можно повесить в классе Group на поле @ManyToMany(mappedBy = "groups") private Setusers = new HashSet (); аннотацию @JsonIgnore Или использовать слой DTO package my.company.model; import javax.persistence.*; import java.util.Date; import java.util.List; import java.util.Set; @Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; private String name; private String surname; private String password; private String email; @Column(name="time_registration") private Date timeRegistration; @ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "users_to_roles", joinColumns = {@JoinColumn(name = "user_id")}, inverseJoinColumns = @JoinColumn(name = "role_id")) private Set roles; @OneToMany(mappedBy = "user", fetch = FetchType.LAZY) private List albums; @ManyToMany(fetch = FetchType.LAZY) @JoinTable(name = "users_to_dialogs", joinColumns = {@JoinColumn(name = "user_id")}, inverseJoinColumns = @JoinColumn(name = "dialog_id")) private List
Комментариев нет:
Отправить комментарий