我有一个与事件实体
具有oneToMany关系的Project实体public class Project {
....
@OneToMany(mappedBy = "dossier", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Event> events;
}
我有一个ProjectService类
@Service
@Transactional
public class ProjectService {
public List<Project> findAll() {
return (List<Project>) projectRepository.findAll();
}
}
和ProjectController
@RestController
@RequestMapping(value = "/projects")
public class ProjectController {
@RequestMapping(method= RequestMethod.GET)
public List<Project> getAllProject() {
return projectService.findAll();
}
}
在我的客户端代码中,我看到项目的事件已加载,我不明白为什么。
我预计在DossierService中方法findAll的事务结束时,实体将被分离。显然,我的实体仍然附着,因为在我的控制器中的jackson序列化期间检索了事件。
答案 0 :(得分:7)
Project.events
默认为延迟加载,因为它是OneToMany
关系。
这并不意味着未加载Project.events
。这意味着只要调用Project.getEvents()
就会加载它。
这发生在JSON序列化中(当ProjectController.getAllProject()
返回其响应时)。
为了防止这种情况,有两种方法:
project.setEvents(null)
返回的每个项目上显式调用ProjectService
(或空列表)。@JsonIgnore
上添加Project.events
注释。编辑:如果您使用的是spring-boot,默认情况下会注册OpenEntityManagerInViewInterceptor:
Spring Web请求拦截器,它将JPA EntityManager绑定到线程以进行整个请求处理。用于“Open EntityManager in View”模式,即允许在Web视图中进行延迟加载,尽管原始事务已经完成。
您可以通过将此行添加到application.properties
:
spring.jpa.open-in-view=false
使用此配置,在休眠会话之外调用getter将导致LazyInitializationException
。
答案 1 :(得分:1)
有两种可能性:
已定义OpenSessionInView
或OpenEntityManagerInView
bean。这种类型的bean分别导致Session
或EntityManager
在调用控制器时打开,并保持打开状态,直到控制器的主体被序列化为止。
它通常被认为是演示/小型应用程序中可接受的行为,但它在大型更复杂的应用程序中非常不受欢迎,因为您的查询应返回视图,控制器或逻辑所需的完全初始化实体。
JSON库启用了一个hibernate插件,它能够在序列化过程中重新附加和保护实体。
否则,一旦服务返回,Session
/ EntityManager
关闭并且实体分离后,您期望的默认行为是准确的。否则预期的行为将是LazyInitializationException
。
答案 2 :(得分:0)
您的实体仍然附加,直到:
但是如果您知道您的事件将在大多数时间加载,那么您应该考虑使用FetchType.EAGER以便一次性获取所有内容。