如何实现JPA双向关联,查询供应商时返回关联产品?
问题:查询Supplier时无法返回关联的Product列表
问题场景
现有两个JPA实体类Product和Supplier配置了双向关联:
Product类代码
@Entity public class Product { @Id private Long productID; @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER) @JsonManagedReference @JoinColumn(name = "fk_supplier") private Supplier supplier; private String description; public Supplier getSupplier() { return supplier; } }
Supplier类代码
@Entity public class Supplier { @Id private Long supplierID; @OneToMany(mappedBy = "supplier") @JsonBackReference private Set<Product> products = new HashSet<>(); private String name; public Set<Product> getProducts() { return products; } }
当前查询Product时能正常返回关联的Supplier信息,示例返回:
{ "productID": 1, "supplier": { "supplierID": 1, "name": "Acer" }, "description": "Gaming chair" }
但查询Supplier时,返回结果缺少关联的Products列表,示例返回:
{ "supplierID": 1, "name": "Acer" }
原因分析
- JSON序列化限制:
@JsonBackReference注解的作用是序列化时忽略当前属性,避免双向关联引发的循环引用问题,因此Supplier的products集合不会被Jackson序列化输出。 - JPA懒加载策略:
@OneToMany注解默认FetchType为LAZY(懒加载),查询Supplier时不会主动加载关联的Product集合,若在Session关闭后访问该集合还会抛出懒加载异常。
解决方案
方案一:调整JSON注解与JPA加载策略
修改Supplier类的注解,用@JsonIgnoreProperties替代@JsonBackReference处理循环引用,同时设置FetchType.EAGER主动加载关联集合:
@Entity public class Supplier { @Id private Long supplierID; // 设置主动加载,并忽略Product中的supplier属性避免循环序列化 @OneToMany(mappedBy = "supplier", fetch = FetchType.EAGER) @JsonIgnoreProperties("supplier") private Set<Product> products = new HashSet<>(); private String name; public Set<Product> getProducts() { return products; } // 推荐添加维护双向关联的方法 public void addProduct(Product product) { products.add(product); product.setSupplier(this); } }
同时可移除Product类中的@JsonManagedReference(@JsonIgnoreProperties已处理循环引用),并补充setter方法方便维护关联:
@Entity public class Product { @Id private Long productID; @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER) @JoinColumn(name = "fk_supplier") private Supplier supplier; private String description; public Supplier getSupplier() { return supplier; } public void setSupplier(Supplier supplier) { this.supplier = supplier; } }
方案二:使用JOIN FETCH查询(性能更优,推荐)
若不想修改默认懒加载策略(EAGER在大数据场景下可能影响性能),可通过JPQL的JOIN FETCH在查询时主动加载关联集合:
- 定义SupplierRepository接口:
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; public interface SupplierRepository extends JpaRepository<Supplier, Long> { @Query("SELECT s FROM Supplier s JOIN FETCH s.products WHERE s.supplierID = :id") Supplier findByIdWithProducts(@Param("id") Long id); }
- 修改
Supplier类的JSON注解:
@Entity public class Supplier { @Id private Long supplierID; @OneToMany(mappedBy = "supplier") @JsonIgnoreProperties("supplier") private Set<Product> products = new HashSet<>(); private String name; public Set<Product> getProducts() { return products; } }
调用findByIdWithProducts方法查询时,会一次性加载Supplier及其关联的Product集合,Jackson也能正常序列化输出products列表。
内容的提问来源于stack exchange,提问作者DwnBrd
相关产品推荐
相关产品推荐

