最有效的数据传输对象与弹簧数据jpa



我有一个实体,在返回给用户之前需要稍微修改。据我所知,最好的方法是使用数据传输对象。

这很好,但后来我添加了一个子实体。我再次为子实体创建了一个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

最新更新