Java 指定是否使用Spring数据延迟加载
我在一个实体中有一个延迟获取类型集合。我使用Spring数据(JpaRepository)访问实体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
@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;
}
@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会话仍然打开(在服务方法内部)时初始化所有属性
您还可以使用以下支持:
因此,您甚至不需要实现:
这些方法可以由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.
}