双向关系导致堆栈溢出错误

问题描述 投票:0回答:1
@Entity
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Portfolio {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Integer id;
    
    @OneToMany(mappedBy="parent" ,fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    @JsonManagedReference
    private Set<PortfolioChildMap> parents;
    
}
@Entity
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PortfolioChildMap {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Integer id;

    @ManyToOne
    @JsonBackReference
    @JoinColumn(name = "parent_id")
    private Portfolio parent;

    @ManyToOne
    @JoinColumn(name = "child_id")
    private Portfolio child;
}

@Data
@Builder
public class PortfolioResponseDto {
    private Integer id;
    private List<PortfolioResponseDto> children;

    public static PortfolioResponseDto toDTO(Portfolio entity) {
        return PortfolioResponseDto.builder()
                .id(entity.getId())
                .children(entity.getParents().stream().map(parent-> toDTO(parent.getChild())).collect(Collectors.toList()))
                .build();
    }
}
public class PortfolioService  {

    private final PortfolioRepository portfolioRepository;

    @Override
    public List<PortfolioResponseDto> getAllPortfolios() {
        return portfolioRepository.findAll().stream()
                .map(PortfolioResponseDto::toDTO).collect(Collectors.toList());
    }

}

portfolio_child_map

enter image description here

如您所见,id 为 33 和 34 的投资组合之间有一个圆圈。 父 Portfolio.id=33 有子 Portfolio.id=34 并且 父 Portfolio.id=34 有子 Portfolio.id=33,这是一个圆圈

当我调用 PortfolioService.getAllPortfolios() 时,它会在 PortfolioResponseDto.toDTO 方法中引发错误。

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.StackOverflowError] with root cause java.lang.StackOverflowError: null

我很确定这是常见错误,但我不知道如何纠正它。所以我有两个问题:

  1. 此问题的正确解决方法是什么,如何避免此类错误。

  2. 就我而言,我可以从父母那里得到第一个孩子并停止。我不知道该怎么做。我应该在存储库中实现自定义 findAll 方法吗?

hibernate jpa spring-data-jpa nhibernate-mapping hibernate-onetomany
1个回答
0
投票

从根本上来说,这不是实体映射所固有的。这只是无限递归的情况。这意味着您必须防止无限递归的发生。有几个选项...您可以...

  1. 确定这不是有效的用例并更正您的数据。
  2. 检测无限递归。如果这是一个有效的用例,请在检测到循环时中止递归算法。 (例如,您可以将一个集合传递到递归方法中。从初始调用的空集合开始,然后检查是否已经处理了当前元素。如果没有,则添加到集合并继续。如果已经处理过,中止)。
  3. 修改您的用例。无需将整个深度转换为 DTO,只需映射一层。然后,如果客户端/调用者需要有关下一个级别的信息,他们可以通过另一个调用来请求。这将递归检测的责任交给了调用者。
© www.soinside.com 2019 - 2024. All rights reserved.