Java 指定是否使用Spring数据延迟加载

Java 指定是否使用Spring数据延迟加载,java,spring,hibernate,jpa,spring-data,Java,Spring,Hibernate,Jpa,Spring Data,我在一个实体中有一个延迟获取类型集合。我使用Spring数据(JpaRepository)访问实体 @Entity public class Parent{ @Id private Long id; @OneToMany(mappedBy = "parentId", fetch = FetchType.LAZY) private Set<Child> children; } 获取父项时应填写“子项”: public Parent getParentWithCh

我在一个实体中有一个延迟获取类型集合。我使用Spring数据(JpaRepository)访问实体

@Entity
public class Parent{
@Id
private Long id;

    @OneToMany(mappedBy = "parentId", fetch = FetchType.LAZY)
    private Set<Child> children;
}
  • 获取父项时应填写“子项”:

     public Parent getParentWithChildren(Long parentId){
         Parent p = repo.findOne(parentId);
         Hibernate.initialize(p.children);
         return p;
    }
    
  • 从RestController返回“父”实体时,会引发以下异常:

    @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[“children”]); 嵌套异常是 com.fasterxml.jackson.databind.JsonMappingException:未能延迟 无法初始化角色的集合:com.entity.Parent.children 初始化代理-无会话(通过引用链: com.entity.Parent[“子项”])


    RestController应该返回一个
    ParentDTO
    ,而不是
    Parent
    实体<可以在事务服务方法中填充code>ParentDTO。

    引发异常,因为JSON序列化程序要求所有属性都已初始化。因此,所有需要返回父级的REST控制器都必须首先初始化属性:

    @RequestMapping("/parent/{parentId}")
    public Parent getParent(@PathVariable("parentId") Long id) {
        return parentService.getParentWithChildren(id);
    }
    
    getParentWithChildren
    服务方法在事务中运行,并且在提交事务时关闭关联的Hibernate会话。这意味着您必须在Hibernate会话仍然打开(在服务方法内部)时初始化所有属性

    您还可以使用以下支持:

    因此,您甚至不需要实现:

  • getParent
  • 带孩子的父母

  • 这些方法可以由Spring数据提供。

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

    public class Child {
        @ManyToOne
        private Parent parentId;
    }
    
    解决方案1:您的代码实际上是正确的,只是您必须使用第二层s(简单POJO类)来将域层传输到客户端/浏览器。如果不这样做,在解决懒惰异常之后,您将遇到一个从父级到子级的循环依赖问题,JSON封送器(Jackson)将尝试编码
    子级
    ,然后编码其
    父级
    ,然后再编码其子级,然后再编码其
    父级
    ,依此类推。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:用于公共属性
    Parent.getChildren()
    ,以便Jackson在编组
    父实例时不会尝试对子实例进行编码。

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

    或者,也可参见下文中的“Spring Data REST中的投影”部分


    您好,但我不想在getParent()方法中获取父对象的子对象。我希望children为null。JPA不是这样工作的,您不应该将collections设置为null。你可以把帕兰特拿来,把它转换成一个没有孩子的DTO,明白了。在我们的例子中,获取集合是一个沉重的负担,管理DTO也是一个沉重的负担。所以我们可能会采用Alan Hay的解决方案。我很高兴你找到了预期的答案。干杯我们实际的实体远比我编写的示例代码复杂和庞大。ParentDTO会给我们带来太多的维护开销。对于实体,在将它们转换为json.Hmm时,您可能会遇到循环依赖性问题。。因此,我要么创建DTO,要么完全删除子项。循环依赖项是通过注释解决的。JsonManagedReference和JsonBackReference用于解决循环依赖项问题。调用
    /parent/{parentId}
    的调用方需要
    父实体的整个复杂性(相当大)?如果没有,那么DTO肯定是首选。我使用了JsonManagedReference和JsonBackReference来管理循环依赖性问题。DTO是唯一的选择吗?我们的实际实体非常庞大和复杂,维护DTO会导致巨大的开销。没有其他解决方案了吗?我添加了另一个解决方案(使用@JsonIgnore)。不是真的,因为在一种方法中我们想要孩子,而在另一种方法中我们不想要。我认为DTO是唯一的出路。我在你的问题中没有看到这一部分。在这种情况下,很明显,您需要一个DTO/Web层(由您决定浏览器的功能)。随着我们的进展,我们可能会添加DTO,但目前我们采用的是Alan Hay的解决方案。我认为link#1非常适合我们的情况。非常感谢。
    
    @Repository
    public interface ParentRepository extends CrudRepository<Parent, Long> {
    
        @EntityGraph(value = "Parent.children", type = EntityGraphType.LOAD)
        Parent getParentWithChildren(Long parentId);
    }
    
    public class Child {
        @ManyToOne
        private Parent parentId;
    }
    
    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.
    }