指定是否使用Spring Data延迟加载

我在实体中有一个懒惰的fetch类型集合。 我正在使用Spring Data(JpaRepository)来访问实体。

@Entity public class Parent{ @Id private Long id; @OneToMany(mappedBy = "parentId", fetch = FetchType.LAZY) private Set children; } 

我想在服务类和当前实现中有两个函数如下:

  1. 获取父级时,“children”应为null

     public Parent getParent(Long parentId){ return repo.findOne(parentId); } 
  2. 取父母时应填写“孩子”:

      public Parent getParentWithChildren(Long parentId){ Parent p = repo.findOne(parentId); Hibernate.initialize(p.children); return p; } 

从RestController返回“Parent”实体时,抛出以下exception:

 @RequestMapping("/parent/{parentId}") public Parent getParent(@PathVariable("parentId") Long id) { Parent p= parentService.getParent(id);//ok till here return p;//error thrown when converting to JSON } 

org.springframework.http.converter.HttpMessageNotWritableException:无法写内容:懒得初始化角色集合:com.entity.Parent.children,无法初始化代理 – 无会话(通过引用链:com.entity.Parent [ “孩子们”]); 嵌套exception是com.fasterxml.jackson.databind.JsonMappingException:懒得初始化一个角色集合:com.entity.Parent.children,无法初始化代理 – 没有Session(通过引用链:com.entity.Parent [“children “])

如果您希望根据用例允许同一域模型的不同JSON表示,那么您可以查看以下内容,这样您就可以在不需要DTO的情况下执行此操作:

https://spring.io/blog/2014/12/02/latest-jackson-integration-improvements-in-spring

或者,另请参阅下面的“Spring Data REST中的预测”部分

https://spring.io/blog/2014/05/21/what-s-new-in-spring-data-dijkstra#projections-in-spring-data-rest

RestController应返回ParentDTO而不是Parent实体。 可以在Transactional服务方法中填充ParentDTO

抛出exception是因为JSON序列化程序要求已初始化所有属性。 因此,所有需要返回Parent的REST控制器必须首先初始化属性:

 @RequestMapping("/parent/{parentId}") public Parent getParent(@PathVariable("parentId") Long id) { return parentService.getParentWithChildren(id); } 

getParentWithChildren服务方法在事务内部运行,并且在提交事务时关闭关联的Hibernate会话。 这意味着您必须在Hibernate Session仍处于打开状态时(在Service方法内)初始化所有属性。

您还可以使用Spring Data实体图形支持:

 @Entity @NamedEntityGraphs(@NamedEntityGraph(name = "Parent.children", attributeNodes = @NamedAttributeNode("children"))) public class Parent{ @Id private Long id; @OneToMany(mappedBy = "parentId", fetch = FetchType.LAZY) private Set children; } 

并且getParentWithChildren方法变为:

 @Repository public interface ParentRepository extends CrudRepository { @EntityGraph(value = "Parent.children", type = EntityGraphType.LOAD) Parent getParentWithChildren(Long parentId); } 

所以,你甚至不需要实现:

  1. 的getParent
  2. getParentWithChildren

这些方法可以由Spring Data提供。

首先,您没有向我们展示Child Java类:我希望该属性名为parentId而不是parent

 public class Child { @ManyToOne private Parent parentId; } 

解决方案1:您的代码实际上是正确的,只需要使用第二层DTO (简单的POJO类)将域层传输到客户端/浏览器。 如果你不这样做,在解决你的懒惰exception后,你会遇到从父到子的循环依赖问题,而JSON编组(jackson)会尝试编码一个Child ,然后是它的Parent ,然后再编译它的子代,然后又是他们的Parent等等。 DTO的一个例子是:

 public class ParentDto { private Long id; private String prop1; public ParentDto(Parent parent) { this.id = parent.id; this.prop1 = parent.prop1; //...other properties } //here come all getters for the properties defined above. } 

解决方案2:将@JsonIgnore用于公共属性Parent.getChildren() ,以便Jackson在编组Parent实例时不会尝试Parent.getChildren()进行编码。