JPA对同一实体的循环依赖导致递归输出

Posted

技术标签:

【中文标题】JPA对同一实体的循环依赖导致递归输出【英文标题】:JPA Circular dependency on same entity resulting in recursive output 【发布时间】:2018-08-24 06:14:01 【问题描述】:

我有一个文件夹类,它又可以有许多子文件夹。在这种情况下,我试图使用单个实体来实现相同的实体。

如下所示。

Folders
----SubFolder
----SubFolder

以下是课程。

FolderData.java

@Entity
@JsonIdentityInfo(generator =ObjectIdGenerators.IntSequenceGenerator.class,property="projectId") 
public class FolderData 

    @Id
    @SequenceGenerator(name = "seq-gen", initialValue = 1)
    @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "seq-gen")
    private Integer parentId;

    private int moduleId;

    private int subProjectId;

    private String folderName;

    private Integer folderId;

    private int projectId;

    @ManyToOne(fetch = FetchType.LAZY,cascade=CascadeType.ALL)
    @JoinColumn(name="folder_child")
    @JsonIgnore
    private FolderData folderData;

    @OneToMany(mappedBy = "folderData")
    @JsonIgnoreProperties("folderList")
    private Set<FolderData> folderList=new HashSet<>();

FodlerController.java

@RestController
@RequestMapping("/folder")
public class FodlerController 

    @Autowired
    private FolderService folderService;

    @GetMapping(produces = "application/json")
    public List<FolderData> getFolderList()
        return folderService.findAllFromTheList();
    


    @PostMapping(produces = "application/json", consumes = "application/json")
    public void createFolder(@RequestBody FolderData folderData) 
        if(folderData.getId()==null && folderData.getFolderId()==null) 
            System.out.println("id is null");
            folderData.setFolderId(new Random().nextInt());
            folderService.save(folderData);
        
        else 
            folderService.doChildAddition(folderData);
        
    

FolderService.java

@Service
public class FolderService 

    @Autowired
    private FolderRepo folderRepo;

    public FolderData save(FolderData folderData) 
        return folderRepo.save(folderData);
    

    public FolderData getFolderDataByParentId(Integer id) 
        return folderRepo.getOne(id);
    

    public List<FolderData> findAllFromTheList() 
        return folderRepo.findAll();
    

    public FolderData getFolderDataByfolderId(Integer folderId) 
        return folderRepo.findFolderByFolderId(folderId);
    

    public void doChildAddition(FolderData childFolder) 
        FolderData parentFolder=folderRepo.findFolderByFolderId(childFolder.getFolderId());
        childFolder.setFolderData(parentFolder);
        FolderData childFolderSaved = folderRepo.saveAndFlush(childFolder);
        //parentFolder.getFolderList().add(folderRepo.getOne(childFolderSaved.getId()));
        //folderRepo.save(parentFolder);
    

创建父级的 Json 请求和收集到的响应,其中包括自动生成的文件夹 ID:


    "moduleId":1,
    "subProjectId":1,
    "folderName":"One",
    "projectId":1


[
  
    "projectId": 0,
    "moduleId": 1,
    "subProjectId": 1,
    "folderName": "One",
    "folderId": 963031296,
    "folderList": [],
    "id": 1
  
]

为父级创建子级并收集响应。


    "moduleId":1,
    "subProjectId":2,
    "folderName":"Two",
    "projectId":1,
     "folderId": -963031296


[
        
            "projectId": 0,
            "moduleId": 1,
            "subProjectId": 1,
            "folderName": "One",
            "folderId": 963031296,
            "folderList": [
                
                    "projectId": 0,
                    "moduleId": 1,
                    "subProjectId": 2,
                    "folderName": "Two",
                    "folderId": 963031296,
                    "id": 2
                
            ],
            "id": 1
        ,
        2
    ]

对于上述响应,由于我使用的是响应,因此我得到了第 2 位

@JsonIdentityInfo(generator =ObjectIdGenerators.IntSequenceGenerator.class,property="parentId") 

否则整个对象会出现而不是 2。

如果我没有使用 JsonIdentityInfo 的示例输出

[
    
        "projectId": 0,
        "moduleId": 1,
        "subProjectId": 1,
        "folderName": "One",
        "folderId": 963031296,
        "folderList": [
            
                "projectId": 0,
                "moduleId": 1,
                "subProjectId": 2,
                "folderName": "Two",
                "folderId": 963031296,
                "id": 2
            
        ],
        "id": 1
    ,
    
        "projectId": 0,
        "moduleId": 1,
        "subProjectId": 2,
        "folderName": "Two",
        "folderId": 963031296,
        "id": 2
    
]

【问题讨论】:

Prash,恐怕你没写问题。 @JánHalaša,已编辑请给我同样的建议。 【参考方案1】:

这很容易,@Prash 由于您在单向依赖项中使用了Set,因此您必须提供连接(依赖)实体的唯一性。任何集合都使用hashCode()equals() 来确定要添加的并发项目的可用性。您的 FolderData 类没有 hashCode()equals() 所以从 JVM 的角度来看,所有反序列化的对象都是相同的,并且由于 Set 的性质,只保留最后一个示例是正常的

【讨论】:

以上是关于JPA对同一实体的循环依赖导致递归输出的主要内容,如果未能解决你的问题,请参考以下文章

WPF UserControl:使多个链接的依赖项属性保持同步,而不会导致递归循环 堆栈溢出

C++模板函数导致循环依赖

spring-循环依赖

解决由于类之间的循环依赖而导致的构建错误

解决由于类之间的循环依赖而导致的构建错误

解决由于类之间的循环依赖而导致的构建错误