首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >由于双向@ManyToMany关系SpringDataJPA上的堆栈溢出错误,我无法创建实体或获取实体列表。

由于双向@ManyToMany关系SpringDataJPA上的堆栈溢出错误,我无法创建实体或获取实体列表。
EN

Stack Overflow用户
提问于 2022-09-09 20:42:03
回答 1查看 51关注 0票数 0

我正在开发一个springboot应用程序。我有两个实体类,组和用户。我还在Group类(拥有实体)和User类中定义了@ManyToMany关系,这样我就可以获取用户所属的所有组。不幸的是,由于以下错误,我无法创建新组或新用户;

代码语言:javascript
复制
{
    "timestamp": "2022-09-09T20:29:22.606+00:00",
    "status": 415,
    "error": "Unsupported Media Type",
    "message": "Content type 'application/json;charset=UTF-8' not supported"
}

当我试图通过调用user.get().getGroups();获取用户所属的所有组时,会出现堆栈溢出错误。

注意:目前,我在Group类和User类中分别拥有@JsonManagedReference和@JsonBackReference。我还尝试在两个类中添加@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id"),但这也不起作用。向@JsonManagedReference和@JsonBackReference添加value参数也不起作用,如下所示。我做错了什么?我遗漏了什么?

这是我的实体类

代码语言:javascript
复制
@Table(name = "`group`") // <- group is a reserved keyword in SQL
public class Group {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @JsonView(Views.Public.class)
    private String name;
    private Integer maximumMembers;

    @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
    @JoinTable(name = "group_user", joinColumns = @JoinColumn(name = "group_id"), inverseJoinColumns = @JoinColumn(name = "user_id"))
    @JsonView(Views.Public.class)
    @JsonManagedReference(value = "group-member")
    private Set<User> groupMembers;
}

这是我的用户实体类

代码语言:javascript
复制
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @JsonView(Views.Public.class)
    private Long id;
    @JsonView(Views.Public.class)
    private String nickname;
    @JsonView(Views.Public.class)
    private String username; // <- Unique user's phone number
    private String password;

    @ElementCollection(targetClass = ApplicationUserRole.class)
    @CollectionTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"))
    @Enumerated(EnumType.STRING)
    @Column(name = "role")
    private Set<ApplicationUserRole> roles;

    @ManyToMany(mappedBy = "groupMembers", fetch = FetchType.LAZY, targetEntity = Group.class)
    @JsonBackReference(value = "user-group")
    private Set<Group> groups;
}

最小的、可复制的示例https://github.com/Java-Techie-jt/JPA-ManyToMany

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-09-12 14:31:05

我找到了这个问题的永久解决方案。对于其他面临类似问题的人来说,这就是我所发现的。首先,我的实体类有@Data Lombok注释。我删除了这一点,因为@Data注释几乎总是加载集合,即使您有FetchType.LAZY

您可以阅读更多关于为什么不应该用@Data注释实体类的文章,https://www.jpa-buddy.com/blog/lombok-and-jpa-what-may-go-wrong/

删除这个注释后,我从关系的两边(两个实体)中删除了@JsonManagedReference@JsonBackReference。然后,我只将@Jsonignore添加到引用端(User类)。这解决了两件事

  1. 创建一个具有用户列表的组,
  2. 将用户列表添加到一个组中,运行良好。

在此之后,我们还有最后一个问题。当我们试图从api中读取一个用户时,我们会得到一个没有关联的组列表的用户,因为我们在用户列表中有@JsonIgnore。为了解决这个问题,我让控制器返回一个新对象。因此,在从我的服务中获取用户之后,我将其映射到一个新的数据传输对象,即我在控制器中返回这个对象。

从这里开始,我使用@JsonView过滤我的答复。

这就是我的类的样子,注意注释中没有@Data

集团

代码语言:javascript
复制
@Builder
@Entity
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Getter
@Setter
@Table(name = "`group`") // <- group is a reserved keyword in SQL
public class Group {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;
    private Integer maximumMembers;

    @ManyToMany(fetch = FetchType.EAGER,
            cascade = {CascadeType.MERGE, CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    @JoinTable(name = "group_user",
            joinColumns = @JoinColumn(name = "group_id"),
            inverseJoinColumns = @JoinColumn(name = "user_id"))
    @JsonView(UserViews.PublicUserDetails.class)
    private Set<User> groupMembers = new HashSet<>();

} 

用户

代码语言:javascript
复制
@Builder
@Entity
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Getter
@Setter
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @JsonView(UserViews.PublicUserDetails.class)
    private Long id;
    @JsonView(UserViews.PublicUserDetails.class)
    private String nickname;
    @JsonView(UserViews.PublicUserDetails.class)
    private String username; // <- Unique user's phone number
    private String password;

    @ElementCollection(targetClass = ApplicationUserRole.class)
    @CollectionTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"))
    @Enumerated(EnumType.STRING)
    @Column(name = "role")
    @JsonView(UserViews.PublicUserDetails.class)
    private Set<ApplicationUserRole> roles;

    @JsonIgnore
    @ManyToMany(mappedBy = "groupMembers", fetch = FetchType.LAZY, targetEntity = Group.class)
    private Set<Group> groups = new HashSet<>();
}

在用户控制器中获取用户的方法

代码语言:javascript
复制
@GetMapping("/get-groups")
    public ResponseEntity<UserRequestResponseDTO> getWithGroups(@RequestParam(name = "userId") Long userId) {
        User user = userService.getWithGroups(userId);
        UserRequestResponseDTO response = UserRequestResponseDTO.builder()
                .nickname(user.getNickname())
                .username(user.getUsername())
                .groups(user.getGroups())
                .build();
        return ResponseEntity.ok().body(response);
    }

希望这能帮到别人

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73667314

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档