我被一個特殊的用例困住了。
需求很容易解釋:我想查詢一個 SQL 視圖,并且視圖中連接的表沒有被任何物體跟蹤,也不應該被跟蹤。我想使用 EntityManager 并將結果自動映射到我的 DTO/POJO。
到目前為止我沒有成功的嘗試:
使用
em.createNativeQuery("select .... from MyView",MyDto.class);Results in Caused by: org.hibernate.MappingException: Unknown entity: MyDto.class另外使用 SqlResultSetMapping
@Data @SqlResultSetMapping(name = "MyDto", classes = { @ConstructorResult(targetClass = MyDto.class, columns = { @ColumnResult(name = "id") }) }) @AllArgsConstructor public class MyDto implements Serializable {Does not work either使用 unwrap 和 createNativeQuery Transformers.aliasToBean
em.createNativeQuery("") .unwrap(SQLQuery.class) .setResultTransformer(Transformers.aliasToBean(MyDto.class));Results in syntax error near "." for whatever reason.與 createNativeQuery 和 AliasToEntityMapResultTransformer 一起使用 unwrap
em.createNativeQuery("") .unwrap(SQLQuery.class) .setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE)Results in syntax error near "." for whatever reason as well.
除此之外,setResultTransformer方法似乎已棄用。
我目前使用較小 DTO 的方法是手動映射,但如何自動執行此操作?
em.createNativeQuery("")
.getResultStream()
.map(o -> {
Object[] cols = (Object[]) o;
//Do some ugly error-prone mapping here and return a new DTO object
return new MyDto();
})
.filter(Objects::nonNull);
uj5u.com熱心網友回復:
一種選擇是將視圖映射到物體。只要確保永遠不要插入或更新它;JPA 不支持它,JPA 提供者可能支持具有提供者特定注釋的只讀物體。您可以使用技巧(如物體偵聽器、插入/更新=假主鍵等)強制執行不插入或更新策略。我會嘗試這個,因為它很簡單。
第二種選擇是照你說的去做,并使用 JPA 的結果映射工具。總而言之,您必須使用本機查詢,因為 JPA 不知道表/視圖。然后將結果的列映射到 DTO @SqlResultSetMapping。
我在一個臨時專案中實作了它,用我的模型展示,以便這個例子是具體的:
首先是 DTO:
public class UserProjectDto {
private long userId;
private long projectId;
private String userName;
private String email;
private String projectName;
// default constructor, probably optional
public UserProjectDto() {}
// all-args constructor, mandatory
public UserProjectDto(long userId, long projectId, String userName, String email, String projectName) {
...
}
// getters, setters
}
然后是(繁瑣的)結果集映射;這必須轉到 JPA 已知的類(例如物體):
@SqlResultSetMappings({
@SqlResultSetMapping(
name = "UserProjectDto", // <- the name is used to reference the mapping
classes = {
@ConstructorResult(
targetClass = UserProjectDto.class,
columns = {
// order of column results matches the arguments of the constructor
// name matches the column in the result set (I like using the property name, but that's my preference)
@ColumnResult(name = "userId", type = long.class),
@ColumnResult(name = "projectId", type = long.class),
@ColumnResult(name = "userName"),
@ColumnResult(name = "email"),
@ColumnResult(name = "projectName")
}
)
}
)
})
public class SomeClassKnownToJpa {
...
}
最后,運行它的代碼:
EntityManager em = ...
Query query = em.createNativeQuery(
// note the "AS" names match the names of the @ColumnResult
"SELECT "
" u.id AS userId,"
" p.id AS projectId,"
" u.name AS userName,"
" u.email AS email,"
" p.name AS projectName "
"FROM APP_USER u, APP_PROJECT p",
// reference the name of the @SqlResultSetMapping
"UserProjectDto"
);
for( Object o : query.getResultList() ) {
UserProjectDto u = (UserProjectDto) o;
System.out.println(u.getUserName() " - " u.getProjectName());
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/403735.html
標籤:
