JPA Hibernate 多对多 IllegalStateException

JPA Hibernate many to many IllegalStateException

我正在尝试创建多对多关系。我有一个 table 'library_branch',我想加入包含 'bookId'、'branchId' 和 'noOfCopies' 的 'BookCopies'。我有一个错误 ErrorMvcAutoConfiguration$StaticView。我不确定我在哪里导致这种无限递归,任何帮助将不胜感激。

2021-11-26 14:54:43.544 ERROR 22348 --- [nio-8080-exec-1] s.e.ErrorMvcAutoConfiguration$StaticView : Cannot render error page for request [/api/branch] and exception [Could not write JSON: Infinite recursion (WhosebugError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (WhosebugError) (through reference chain: com.example.demo.branch.Branch["inventory"]->org.hibernate.collection.internal.PersistentSet[0]->com.example.demo.inventory.Inventory["branch"]->com.example.demo.branch.Branch["inventory"]

InventoryId.java

package com.example.demo.inventory;

...

@Data @AllArgsConstructor
@NoArgsConstructor
@Embeddable
public class InventoryId implements Serializable {

    @Column(name = "book_id")
    private int bookId;

    @Column(name = "branch_id")
    private int branchId;

}

Inventory.java

package com.example.demo.inventory;

...

@Entity(name="Inventory")
@Table(name = "tblBookCopies")
public class Inventory {
    @EmbeddedId
    private InventoryId id;

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("branch_id")
    private Branch branch;

    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("book_id")
    private Book book;

    @Column(name="no_of_copies")
    private int qty;

    public Inventory( Branch branch, Book book, int qty) {
        this.id = new InventoryId(branch.getId(),book.getId());
        this.branch = branch;
        this.book = book;
        this.qty = qty;
    }

    ...
}

Branch.java

package com.example.demo.branch;

...

@Entity(name="Branch")
@Table(name="tblLibraryBranch")
public class Branch {

    @Id
    @Column(name="id")
    private int id;
    @Column(name="name")
    private String name;
    @Column(name="address")
    private String address;
    @OneToMany(mappedBy = "branch", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Inventory> inventory = new HashSet<>();

    ...
}

问题是您的 Inventory 指向 Branch 而您的 Branch 引用了 Inventory。问题出在杰克逊身上,你需要解释一下如何遵循这些形成循环依赖的引用。

选项 1)

不要使用实体进行序列化。通常您不想公开数据库实体 - 这些应该是内部对象。如果将它们映射到某个 DTO 表示并序列化,问题就会消失。

选项 2)

向 Jackson 解释如何遵循这些参考资料 - 您需要查看 JsonManagedReference and JsonBackReference

在你的情况下你需要尝试类似的东西(但也要检查这个 blogpost 中的数字 7):

@Entity(name="Inventory")
@Table(name = "tblBookCopies")
public class Inventory {
    ... 
    @ManyToOne(fetch = FetchType.LAZY)
    @MapsId("branch_id")
    @JsonManagedReference // <-------- THIS
    private Branch branch;
    ...
}

@Entity(name="Branch")
@Table(name="tblLibraryBranch")
public class Branch {
    ...
    @OneToMany(mappedBy = "branch", cascade = CascadeType.ALL, orphanRemoval = true)
    @JsonBackReference // <--------- THIS
    private Set<Inventory> inventory = new HashSet<>();
    ...
}