我正在用一个简单的域模型构建一个应用程序。该项目使用springboot和jpa。部分模型如下:
abstractentity.java文件:
@MappedSuperclass
public abstract class AbstractEntity {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
...
}
任务.java:
@Entity
public class Task extends AbstractEntity {
...
@OneToMany(mappedBy = "task")
private List<TaskNote> notes = new ArrayList<>();
@OneToMany(mappedBy = "task")
private List<StateChangeHistory> stateHistory = new ArrayList<>();
...
}
tasknote.java文件:
@Entity
public class TaskNote extends AbstractEntity {
...
@ManyToOne
private Task task;
...
}
statechangehistory.java:
@Entity
public class StateChangeHistory extends AbstractEntity {
@ManyToOne
private Task task;
...
}
mainview.java(我正在使用vaadin):
@Route("")
@CssImport("./styles/shared-styles.css")
public class MainView extends VerticalLayout {
private Grid<Task> grid = new Grid<>(Task.class);
private TaskService taskService;
public MainView(TaskService taskService) {
this.taskService = taskService;
...
updateGrid();
}
...
private void updateGrid() {
grid.setItems(taskService.findAll());
}
}
我正在构建主视图,它当前只有一个 Task
s。视图使用 @Service
通过 JpaRepository
实施。
taskrepository.java文件:
public interface TaskRepository extends JpaRepository<Task, Long> {
}
其他类字段也有类似的存储库类(例如。 TaskNote
).
taskservice.java文件:
@Service
public class TaskService {
private TaskRepository taskRepository;
public TaskService(TaskRepository taskRepository) {
this.taskRepository = taskRepository;
}
...
// Load some test data.
@PostConstruct
public void populateTestData() {
if (taskRepository.count() == 0) {
Task task = null;
TaskNote note = null;
task = new Task("Task-1");
note = new TaskNote();
note.setNote("note");
task.getNotes().add(note);
taskRepository.save(task);
taskRepository.save(new Task("TEST-2"));
}
}
}
我遇到了一个 LazyInitializationException
,这显然是一个相当普遍的现象-至少对我们jpa/HibernateNoobs来说。
例外情况如下:
[DEBUG] 2020-11-20 14:50:52.801 [http-nio-8080-exec-2] DispatcherServlet - Failed to complete request: javax.servlet.ServletException: com.vaadin.flow.server.ServiceException: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.mycompany.tasks.backend.entity.Task.notes, could not initialize proxy - no Session
[ERROR] 2020-11-20 14:50:52.803 [http-nio-8080-exec-2] [dispatcherServlet] - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [com.vaadin.flow.server.ServiceException: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.mycompany.tasks.backend.entity.Task.notes, could not initialize proxy - no Session] with root cause
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.mycompany.tasks.backend.entity.Task.notes, could not initialize proxy - no Session
我开始在google上搜索,发现了一篇有趣的文章,讨论了处理这个问题的正确方法,以及不应该使用的“解决方案”。
以下是链接:https://thorben-janssen.com/lazyinitializationexception/#how_to_fix_the_lazyinitializationexception
我真的不明白这篇文章是怎么写的。我对java中的数据持久性知之甚少。我一直认为spring等的使用使这项工作比过去简单得多。
我从我所看到和读到的东西中得到的要点是,当我得到“父”时,我需要得到下属(例如任务的注解)数据。我想这是有道理的,但我不知道该怎么办。本文中提供的示例似乎需要编写需要相当好的hibernate或jpa知识的代码。这似乎也违背了spring等旨在提供的“简单性”原则。也许没那么复杂,但我知道的还不足以做出判断。
我正在寻找理解和方法来找到一个解决办法,使这项工作。
更新1-11/24/2020
我决定试着用 @NamedEntityGraph
来看看这是否有帮助。然而,我怀疑要想让它真正起作用,我需要用一个 EntityManager
示例。我不确定我应该在哪里使用实体管理器-在 @Service
或者在 TaskRepository
. 我还需要做更多的研究来了解如何使用它。这方面的任何建议都会有帮助。
这只是我的印象,但这似乎增加了代码的复杂性,以建立专门的查询逻辑,以便获得 Task
以及所有关联的子对象。这些都是为了避免 LazyInitializationException
. spring和/或jpa/hibernate在没有额外定制的情况下不能处理这个问题吗?
我错过了什么?
更新2-11/24/2020
我修改代码如下:
任务.java:
@NamedEntityGraph(name = "graph.task", attributeNodes = { @NamedAttributeNode("notes"),
@NamedAttributeNode("stateHistory") })
public class Task extends AbstractEntity {
...
}
taskrepository.java文件:
public interface TaskRepository extends JpaRepository<Task, Long>, TaskRepositoryCustom {
}
taskrepositorycustom.java文件:
public interface TaskRepositoryCustom {
List<Task> findAll();
}
taskrepositorycustomimpl.java文件:
@Repository
@Transactional
public class TaskRepositoryCustomImpl implements TaskRepositoryCustom {
@PersistenceContext
private EntityManager entityManager;
@Override
public List<Task> findAll() {
EntityGraph<?> graph = entityManager.getEntityGraph("graph.task");
TypedQuery<Task> query = entityManager.createQuery("select t from Task t", Task.class)
.setHint("javax.persistence.fetchgraph", graph);
return query.getResultList();
}
}
这似乎解决了问题 LazyInitializationException
但产生了一个新问题:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.mycompany.tasks.ui.MainView': Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.mycompany.tasks.ui.MainView]: Constructor threw exception; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags: [com.mycompany.tasks.backend.entity.Task.stateHistory, com.mycompany.tasks.backend.entity.Task.notes]; nested exception is java.lang.IllegalArgumentException: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags: [com.mycompany.tasks.backend.entity.Task.stateHistory, com.mycompany.tasks.backend.entity.Task.notes]
暂无答案!
目前还没有任何答案,快来回答吧!