Spring Data JPA @OneToMany 无限循环异常

6

使用Spring Data JPA和Hibernate作为提供程序的OneToMany关系会导致无限循环

问题不在于异常类型,而在于导致此异常的无限循环

Infinite loop

我尝试了@JsonIgnoreProperties,但出现了另一个错误 => 'Could not write JSON: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer'

引用解决方案的帖子没有解决我的问题。

一种方法是使用@JsonManagedReference和@JsonBackReference,这确实停止了递归,但将对象(“myUser”实体中的UserGroup)从结果中排除,而我需要该对象。

另一种方法是覆盖ToString方法,但我没有这样做。

另外一个人解释了为什么会发生无限循环,并建议不要那样做。我引用:“尝试从返回的模型创建DTO或值对象(简单POJO)而不带循环,然后返回它。”

这篇文章 @JsonIgnore和@JsonBackReference,@JsonManagedReference之间的区别解释了区别,但这样做会出现与第一个方法相同的问题。

'myUser'实体

@Entity
public class MyUser {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  private String firstName;
  private String lastName;
  private String email;
  private Integer age;

  //@JsonIgnoreProperties({"myUsers"})
  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "userGroupId")
  private UserGroup userGroup;

"

用户组实体

"
@Entity
public class UserGroup {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private Integer groupOrder;
    @OneToMany
    (
        mappedBy = "userGroup", 
        cascade = CascadeType.ALL, 
        orphanRemoval = true
    )
    private List<MyUser> myUsers;

你还需要帮忙吗? - VK321
3个回答

4

请按照以下方法修改您的MyUser类中的getUserGroup()方法。

@Entity
public class MyUser 
{    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String firstName;
    private String lastName;
    private String email;
    private Integer age;

    //@JsonIgnoreProperties({"myUsers"})
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "userGroupId")
    private UserGroup userGroup;

    public UserGroup getUserGroup() 
    {
        userGroup.setMyUsers(null);
        return userGroup;
    }
}

我在UserGroup中添加了更新后的getter方法,而不是MyUser,但是你的建议指引了我找到了解决方案,所以谢谢 :) - sunil yaduvanshi
可以工作!只限于ManyToOne。 - gvd

2

你需要在@OneToMany上添加@JsonIgnore注解,就像这样:

@JsonIgnore   
@OneToMany
    (
        mappedBy = "userGroup", 
        cascade = CascadeType.ALL, 
        orphanRemoval = true
    )
    private List<MyUser> myUsers;

感谢您的回复。@JsonIgnore 的问题是,当我获取“UserGroup”实体时,它会完全忽略“myUsers”字段在我的结果中的存在。而在执行后者时,我需要该字段出现在我的结果中。 - Merv

1
我认为我已经理解了你的问题。你想获取MyUser,包括userGroup数据,但又不想产生循环引用
根据你列举的解决方案,我建议你仍然使用@JsonBackReference@JsonManagedReference防止递归在你的实体中,并且对于你的问题的解决方案,你可以尝试使用一个映射器(MapStruck)在从服务检索数据时将userGroup详细信息映射到DTO中。 DTOs:
public class MyUserDto {
    private Long id;
    private String firstName;
    private String lastName;
    private String email;
    private Integer age;
    private UserGroupDto userGroupDto;
}

public class UserGroupDto {
    private Long id;
    private Integer groupOrder;
}

映射器(MapStruck):

@Mapper(componentModel = "spring")
public interface MyUserMapper {

    MyUserMapper INSTANCE = Mappers.getMapper(MyUserMapper.class);
    
    UserGroupDto userGroupToDto(UserGroup userGroup);

    @Mapping(source = "myUser.userGroup", target = "userGroupDto")
    MyUserDto myUserToDto(MyUser myUser);
}

从您的repository检索数据后,您可以调用myUserToDto方法将实体映射到DTO。这只是解决问题的一种方式。

谢谢兄弟。我确实在一段时间前用DTO解决了这个问题。换句话说,我建议停止直接使用实体获取数据,以节省处理这些错误和忽略属性等配置的时间。使用DTO实际上更容易,您只需获取所需的数据即可获得更多的灵活性。如果您正在使用Spring,请使用Lombok注释包。谢谢。 - Merv
当然没问题,兄弟! - Donato Amasa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接