我有一个实体,在返回给用户之前需要稍微修改。据我所知,最好的方法是使用数据传输对象。
这很好,但后来我添加了一个子实体。我再次为子实体创建了一个DTO。这是存储库的代码:
@Repository
public interface DrawingReleaseRepository extends CrudRepository<DrawingRelease, Integer> {
@Query("SELECT new com.engineering.dto.drawings.DrawingReleaseDTO("
+ "dwgrel.drawingReleaseID,"
+ "relType"
+ ") FROM DrawingRelease dwgrel "
+ "JOIN dwgrel.releaseType relType "
+ "WHERE dwgrel.drawingReleaseID = ?1")
DrawingReleaseDTO getDrawingRelease(int drawingReleaseID);
}
DrawingReleaseDTO的构造函数是:
public DrawingReleaseDTO(int drawingReleaseID, DrawingReleaseType releaseType) {
this.drawingReleaseID = drawingReleaseID;
this.releaseType = new DrawingReleaseTypeDTO(releaseType);
}
在我的服务层中,我现在可以操作数据并将其返回到客户端,但更改不会持久化到数据库中(这正是我想要的(:
@Override
public DrawingReleaseDTO findByID(int id) {
DrawingReleaseDTO dto = repository.getDrawingRelease(id);
dto.getReleaseType().setCustom1(true);
return dto;
}
这种情况的问题是效率不是很高。我的意思是Hibernate执行两个查询——一个用于DrawingRelease
,一个用于DrawingReleaseType
。
我认为解决这个问题的方法是指定JOIN FETCH dwgrel.releaseType relType
,因为这应该强制hibernate在一次快照中获取所有数据,但这会产生错误:
查询指定了联接获取,但获取的所有者选择列表中不存在关联
有没有一种方法可以使用DTO,包括子实体的数据,并让它都使用高效的查询?
问题是您混合了DTO和实体。
DTO不应该引用实体,第二个查询来自初始化子实体。
此外,将实体传递给DTO是anti-pattern
:
this.releaseType = new DrawingReleaseTypeDTO(releaseType);
您需要使用列投影来构造DTO。
这是Blaze Persistence实体视图的完美用例,它将完全按照您的意愿执行操作,并通过生成只获取相关属性的JPQL/HQL查询来提高性能。虽然我不知道你的模型,但据我所知,你的模型使用实体视图可能看起来像这个
@EntityView(DrawingRelease.class)
public interface DrawingReleaseDTO
int getDrawingReleaseID();
DrawingReleaseTypeDTO getReleaseType();
@EntityView(DrawingReleaseType.class)
interface DrawingReleaseTypeDTO {
boolean isCustom1();
}
}
正确设置后,您可以将该实体视图与spring数据存储库一起使用
interface DrawingReleaseRepository extends JpaRepository<DrawingReleaseDTO, Long> {
}
DrawingReleaseDTO dto = drawingReleaseRepository.findById(id);
它将生成类似的JPQL/HQL查询
SELECT drawingRelease.id, drawingReleaseType.custom1
FROM DrawingRelease drawingRelease
LEFT JOIN drawingRelease.drawingReleaseType drawingReleaseType
WHERE drawingRelease.id = :id