[英]I am unable to create entity or fetch list of entities due to stack overflow error on bi-directional @ManyToMany relationship SpringDataJPA
我正在開發一個springboot應用程序。 我有 2 個實體類,組和用戶。 我還在組 class(擁有實體)和用戶 class 中定義了 @ManyToMany 關系,這樣我就可以獲取用戶所屬的所有組。 不幸的是,由於以下錯誤,我無法創建新組或新用戶;
{
"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")
,但這也不起作用。 如下所示,將 value 參數添加到 @JsonManagedReference 和 @JsonBackReference 也不起作用。 我究竟做錯了什么? 我錯過了什么?
這是我的集團實體 class
@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;
}
這是我的用戶實體 class
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;
}
我找到了這個問題的永久解決方案。 對於其他面臨類似問題的人,這就是我發現的。 首先,我的實體類有@Data
Lombok 注釋。 我刪除了這個,因為@Data
注釋幾乎總是加載 collections ,即使你有FetchType.LAZY
。
您可以在此處閱讀更多關於為什么不應該使用@Data
注釋您的實體 class https://www.jpa-buddy.com/blog/lombok-and-jpa-what-may-go-wrong/
刪除此注釋后,我從關系的雙方(兩個實體)中刪除@JsonManagedReference
和@JsonBackReference
。 然后我將@Jsonignore
添加到僅引用端(用戶類)。 這解決了兩件事
在此之后,我們剩下最后一個問題。 當我們嘗試從 api 讀取用戶時,我們得到的用戶沒有他們所屬的組的關聯列表,因為我們在用戶列表中有@JsonIgnore
。 為了解決這個問題,我讓 controller 返回一個新的 object。 所以在從我的服務中獲取用戶之后,我將 map 它轉移到一個新的數據傳輸 object 中,我在 Z5904C103F2C06E1 中返回這個 object。
從這里我使用@JsonView
過濾我的回復。
這就是我的類的外觀,注意注釋中沒有@Data
。
團體
@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<>();
}
用戶
@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<>();
}
在用戶 controller 中獲取用戶的方法
@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);
}
希望這可以幫助某人
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.