Spring Boot获取Contrat实体完整数据:Angular5缺失关联Project字段
我现在从Angular5向Spring Boot发送GET请求,想要获取Contrat实体的全部元素,但返回结果里缺少前端需要的project字段,数据库里是存在对应关联数据的。相关代码和返回结果如下:
Contrat实体代码
@Entity @Data @AllArgsConstructor @NoArgsConstructor public class Contrat implements Serializable{ @Id @GeneratedValue private Long id; private Date dateDebut ; private Date dateFin ; private boolean valid; @ManyToOne @JoinColumn(name = "Id_Project") @JsonBackReference(value="projet-contrat") private Project project; @ManyToOne @JoinColumn(name = "Id_AppUser") @JsonBackReference(value="appuser-contrat") private AppUser appUser; }
Contrat仓库代码
public interface ContratRepo extends JpaRepository<Contrat,Long> { @Query("select from Contrat c where c.appUser = :userApp") public Page<Contrat> chercherContrat(@Param("userApp") AppUser userApp , Pageable pageable); }
Angular中返回结果示例
{id: 1, dateDebut: 1526083200000, dateFin: 1526083200000}
请问是否需要发送两次GET请求分别获取两个实体数据,或是有更优的解决方法?
完全不需要发送两次请求,有几种更优雅的方式可以让你在一次请求中拿到包含project关联数据的Contrat结果:
1. 调整JSON序列化注解
你在project字段上使用的@JsonBackReference注解,主要作用是避免实体间的循环引用,但同时也会把该字段排除在序列化输出之外。可以换成更灵活的@JsonIgnoreProperties来控制序列化:
@ManyToOne @JoinColumn(name = "Id_Project") @JsonIgnoreProperties("contrats") // 假设Project实体中有contrats集合字段,忽略它避免循环引用 private Project project;
这样Spring Boot返回的JSON就会包含完整的project数据(只要Project实体的字段没有被其他忽略注解限制)。
2. 使用JOIN FETCH主动加载关联数据
修改JPA查询语句,通过JOIN FETCH强制在查询Contrat的同时加载关联的Project,避免懒加载导致序列化时无法获取数据:
// 添加查询所有Contrat并附带Project的方法 @Query("SELECT c FROM Contrat c JOIN FETCH c.project") List<Contrat> findAllWithProject(); // 对现有的chercherContrat方法进行改造 @Query("SELECT c FROM Contrat c JOIN FETCH c.project WHERE c.appUser = :userApp") Page<Contrat> chercherContratWithProject(@Param("userApp") AppUser userApp, Pageable pageable);
⚠️ 注意:当JOIN FETCH和Pageable一起使用时,可能会出现重复数据的问题。如果遇到这种情况,可以先分页查询Contrat的id列表,再根据id批量查询带关联数据的实体,或者调整查询逻辑。
3. 利用JPA实体图(Entity Graph)精准控制加载
通过定义实体图,可以指定查询时需要加载的关联字段,既灵活又能避免不必要的性能开销:
首先在Contrat实体上定义实体图:
@Entity @Data @AllArgsConstructor @NoArgsConstructor @NamedEntityGraph(name = "Contrat.withProject", attributeNodes = @NamedAttributeNode("project")) public class Contrat implements Serializable{ // 原有字段保持不变 }
然后在Repository方法上标注使用该实体图:
@EntityGraph(value = "Contrat.withProject") List<Contrat> findAll(); @EntityGraph(value = "Contrat.withProject") Page<Contrat> chercherContrat(@Param("userApp") AppUser userApp, Pageable pageable);
这种方式可以根据不同的业务需求定义多个实体图,按需加载关联数据,是比较推荐的方案。
总结来说,以上三种方法都能帮你在一次GET请求中获取包含Project字段的Contrat数据,不用拆分请求。优先推荐实体图或JOIN FETCH的方式,能更精准地控制数据加载,提升接口性能。
内容的提问来源于stack exchange,提问作者dEs12ZER

