我有一个带有Spring Data JPA的Spring Boot应用,该应用具有hibernate和MySQL作为数据存储。
我的应用程序具有3层:
应用服务的作用是在给定一些业务逻辑的情况下将支持休眠的POJO转换为DTO。
POJO
SchoolClass.java
@Column
Long id;
@Column
String name;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "schoolClass")
List<Book> books;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "schoolClass")
List<Student> students;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "schoolClass")
List<Schedule> schedules;
域服务-我的交易边界在域服务层。
SchoolClassService.java
@Autowired
private SchoolClassRepository repository;
@Transactional(readOnly = true)
public SchoolClass getClassById(Long id) {
return repository.findById(id);
}
应用服务
SchoolClassAppService.java
@Autowired
private SchoolClassService domainService;
public SchoolClassDto getClassById(Long id) {
SchoolClass schoolClass = domainService.getClassById(id);
// convert POJO to DTO;
return SchoolClassDto;
}
我的问题是,当我尝试在SchoolClassAppService中访问它们时,SchoolClass上的子实体有时为空。不是全部,但是在这三个中,两个可以正常工作,但是第三个是空的。我试图标记要急切获取的子级列表,但是显然,在Hibernate开始引发异常之前,只能急切地获取两个集合,而且始终加载所有对象听起来也不是一种好习惯。我没有得到LazyInitializationException
,只是列表为空。
我试图只在域服务方法中的所有列表上调用getter,然后再返回它以仅加载POJO的所有数据,但这似乎不是一种干净的做法。
是否有任何可用的模式可以使事务边界尽可能靠近持久层,同时即使在事务关闭后仍然可以处理数据?
答案 0 :(得分:1)
不知道为什么有时您的收藏集为空,但也许只是数据如何?
我正是为此用例创建了Blaze-Persistence Entity Views。您实际上将JPA实体的DTO定义为接口,并将其应用于查询。它支持映射嵌套的DTO,集合等,本质上是您期望的所有内容,此外,它还将提高查询性能,因为它将生成查询,仅提取您实际为DTO所需的数据。
您的示例的实体视图如下
@EntityView(SchoolClass.class)
interface SchoolClassDto {
String getName();
List<BookDto> getBooks();
}
@EntityView(Book.class)
interface BookDto {
// Whatever data you need from Book
}
查询看起来像这样
List<SchoolClassDto> dtos = entityViewManager.applySetting(
EntityViewSetting.create(SchoolClassDto.class),
criteriaBuilderFactory.create(em, SchoolClass.class)
).getResultList();
请记住,DTO不仅应复制您的实体,还应设计为适合您的特定用例。