[英]How to map the result set of a JPA NativeQuery to a POJO using SqlResultSetMapping
我正在尝试使用@SqlResultSetMapping 和@ConstructorResult 将本机查询的结果映射到POJO。 这是我的代码:
@SqlResultSetMapping(name="foo",
classes = {
@ConstructorResult(
targetClass = Bar.class,
columns = {
@ColumnResult(name = "barId", type = Long.class),
@ColumnResult(name = "barName", type = String.class),
@ColumnResult(name = "barTotal", type = Long.class)
})
})
public class Bar {
private Long barId;
private String barName;
private Long barTotal;
...
然后在我的 DAO 中:
Query query = em.createNativeQueryBar(QUERY, "foo");
... set some parameters ...
List<Bar> list = (List<Bar>) query.getResultList();
我读过这个功能只在 JPA 2.1 中受支持,但这就是我正在使用的。 这是我的依赖:
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
我找到了一些资源,包括这个: @ConstructorResult mapping in jpa 2.1 。 但我仍然没有任何运气。
我错过了什么? 为什么找不到SqlResultSetMapping?
javax.persistence.PersistenceException: org.hibernate.MappingException: Unknown SqlResultSetMapping [foo]
@SqlResultSetMapping
注解不应放在 POJO 上。 把它放在(任何) @Entity
类。 “未知的 SqlResultSetMapping [foo]”告诉您,JPA 提供程序没有看到名称为“foo”的任何映射。 请参阅我的另一个答案以获取正确的示例
简短的工作示例:
DTO POJO 类
@lombok.Getter @lombok.AllArgsConstructor public class StatementDto { private String authorName; private Date createTime; }
存储库 bean:
@Repository public class StatementNativeRepository { @PersistenceContext private EntityManager em; static final String STATEMENT_SQLMAP = "Statement-SQL-Mapping"; public List<StatementDto> findPipelinedStatements() { Query query = em.createNativeQuery( "select author_name, create_time from TABLE(SomePipelinedFun('xxx'))", STATEMENT_SQLMAP); return query.getResultList(); } @SqlResultSetMapping(name= STATEMENT_SQLMAP, classes = { @ConstructorResult(targetClass = StatementDto.class, columns = { @ColumnResult(name="author_name",type = String.class), @ColumnResult(name="create_time",type = Date.class) } ) }) @Entity class SQLMappingCfgEntity{@Id int id;} // <- workaround }
我可以这样做:
Session session = em().unwrap(Session.class);
SQLQuery q = session.createSQLQuery("YOUR SQL HERE");
q.setResultTransformer( Transformers.aliasToBean( MyNotMappedPojoClassHere.class) );
List<MyNotMappedPojoClassHere> postList = q.list();
将@Entity
添加到 DTO POJO 的问题在于,它将在您的数据库中创建一个您不需要的表。 必须将@Id
和瞬态关键字添加到必要的字段也是一件麻烦事。 一个简单的解决方案是将您的@SqlResultSetMapping
移动到抽象类。
@MappedSuperclass
@SqlResultSetMapping(name="foo",
classes = {
@ConstructorResult(
targetClass = Bar.class,
columns = {
@ColumnResult(name = "barId", type = Long.class),
@ColumnResult(name = "barName", type = String.class),
@ColumnResult(name = "barTotal", type = Long.class)
})
})
public abstract class sqlMappingCode {}
不要忘记添加@MappedSuperclass
。 这将确保 Hibernate 自动连接您的映射。
更新:此功能在 Hibernate 5.4.30 中被破坏。最终,创建了 Jira 票证HHH-14572
更新 2:看起来此功能在 5.4.30.Final 之后永久中断。 新的解决方案,您需要添加一个带有表名的@Entity
,然后创建两个类:
public class CustomSchemaFilterProvider implements SchemaFilterProvider {
// implement code, use CustomSchemaFilter below
}
然后创建一个单例自定义过滤器
public class CustomSchemaFilter implements SchemaFilter {
// implement code, check for table names you don't want in your schema
}
在您的 JPA 配置文件集中:
jpaProp.put(Environment.HBM2DDL_FILTER_PROVIDER, "com.your.package.CustomSchemaFilterProvider");
// OR
hibernate.hbm2ddl.schema_filter_provider=com.your.package.CustomSchemaFilterProvider
这将确保您的新@Entity
在映射期间被休眠忽略
用休眠 5.6.9.Final 测试
假设我们的数据库中有以下post
和post_comment
表:
SqlResultSetMapping
SqlResultSetMapping
JPA 注释如下所示:
@Repeatable(SqlResultSetMappings.class)
@Target({TYPE})
@Retention(RUNTIME)
public @interface SqlResultSetMapping {
String name();
EntityResult[] entities() default {};
ConstructorResult[] classes() default {};
ColumnResult[] columns() default {};
}
SqlResultSetMapping
注解是可重复的,并在实体类级别应用。 除了采用 Hibernate 用来注册映射的唯一名称之外,还有三个映射选项:
EntityResult
ConstructorResult
ColumnResult
接下来,我们将了解这三个映射选项是如何工作的,以及您需要使用它们的用例。
EntityResult
选项允许您将 JDBC ResultSet
列映射到一个或多个 JPA 实体。
假设我们想要获取前 5 个Post
实体以及与给定title
模式匹配的所有关联PostComment
实体。
正如我在本文中所解释的,我们可以使用DENSE_RANK
SQL 窗口函数来了解如何过滤post
和post_comment
连接记录,如下面的 SQL 查询所示:
SELECT *
FROM (
SELECT
*,
DENSE_RANK() OVER (
ORDER BY
"p.created_on",
"p.id"
) rank
FROM (
SELECT
p.id AS "p.id", p.created_on AS "p.created_on",
p.title AS "p.title", pc.post_id AS "pc.post_id",
pc.id as "pc.id", pc.created_on AS "pc.created_on",
pc.review AS "pc.review"
FROM post p
LEFT JOIN post_comment pc ON p.id = pc.post_id
WHERE p.title LIKE :titlePattern
ORDER BY p.created_on
) p_pc
) p_pc_r
WHERE p_pc_r.rank <= :rank
但是,我们不想返回标量列值的列表。 我们想从这个查询中返回 JPA 实体,所以我们需要配置@SqlResultSetMapping
注解的entities
属性,像这样:
@NamedNativeQuery(
name = "PostWithCommentByRank",
query = """
SELECT *
FROM (
SELECT
*,
DENSE_RANK() OVER (
ORDER BY
"p.created_on",
"p.id"
) rank
FROM (
SELECT
p.id AS "p.id", p.created_on AS "p.created_on",
p.title AS "p.title", pc.post_id AS "pc.post_id",
pc.id as "pc.id", pc.created_on AS "pc.created_on",
pc.review AS "pc.review"
FROM post p
LEFT JOIN post_comment pc ON p.id = pc.post_id
WHERE p.title LIKE :titlePattern
ORDER BY p.created_on
) p_pc
) p_pc_r
WHERE p_pc_r.rank <= :rank
""",
resultSetMapping = "PostWithCommentByRankMapping"
)
@SqlResultSetMapping(
name = "PostWithCommentByRankMapping",
entities = {
@EntityResult(
entityClass = Post.class,
fields = {
@FieldResult(name = "id", column = "p.id"),
@FieldResult(name = "createdOn", column = "p.created_on"),
@FieldResult(name = "title", column = "p.title"),
}
),
@EntityResult(
entityClass = PostComment.class,
fields = {
@FieldResult(name = "id", column = "pc.id"),
@FieldResult(name = "createdOn", column = "pc.created_on"),
@FieldResult(name = "review", column = "pc.review"),
@FieldResult(name = "post", column = "pc.post_id"),
}
)
}
)
有了SqlResultSetMapping
,我们可以像这样获取Post
和PostComment
实体:
List<Object[]> postAndCommentList = entityManager
.createNamedQuery("PostWithCommentByRank")
.setParameter("titlePattern", "High-Performance Java Persistence %")
.setParameter("rank", POST_RESULT_COUNT)
.getResultList();
而且,我们可以验证实体是否被正确获取:
assertEquals(
POST_RESULT_COUNT * COMMENT_COUNT,
postAndCommentList.size()
);
for (int i = 0; i < COMMENT_COUNT; i++) {
Post post = (Post) postAndCommentList.get(i)[0];
PostComment comment = (PostComment) postAndCommentList.get(i)[1];
assertTrue(entityManager.contains(post));
assertTrue(entityManager.contains(comment));
assertEquals(
"High-Performance Java Persistence - Chapter 1",
post.getTitle()
);
assertEquals(
String.format(
"Comment nr. %d - A must read!",
i + 1
),
comment.getReview()
);
}
@EntityResult
在通过 SQL 存储过程获取 JPA 实体时也很有用。 查看这篇文章了解更多详情。
假设我们要执行一个聚合查询,计算每个post
的post_coment
记录数并返回post
title
以用于报告目的。 我们可以使用下面的 SQL 查询来实现这个目标:
SELECT
p.id AS "p.id",
p.title AS "p.title",
COUNT(pc.*) AS "comment_count"
FROM post_comment pc
LEFT JOIN post p ON p.id = pc.post_id
GROUP BY p.id, p.title
ORDER BY p.id
我们还希望将帖子标题和评论数封装在以下 DTO 中:
public class PostTitleWithCommentCount {
private final String postTitle;
private final int commentCount;
public PostTitleWithCommentCount(
String postTitle,
int commentCount) {
this.postTitle = postTitle;
this.commentCount = commentCount;
}
public String getPostTitle() {
return postTitle;
}
public int getCommentCount() {
return commentCount;
}
}
要将上述 SQL 查询的结果集映射到PostTitleWithCommentCount
DTO,我们可以使用@SqlResultSetMapping
注解的classes
属性,如下所示:
@NamedNativeQuery(
name = "PostTitleWithCommentCount",
query = """
SELECT
p.id AS "p.id",
p.title AS "p.title",
COUNT(pc.*) AS "comment_count"
FROM post_comment pc
LEFT JOIN post p ON p.id = pc.post_id
GROUP BY p.id, p.title
ORDER BY p.id
""",
resultSetMapping = "PostTitleWithCommentCountMapping"
)
@SqlResultSetMapping(
name = "PostTitleWithCommentCountMapping",
classes = {
@ConstructorResult(
columns = {
@ColumnResult(name = "p.title"),
@ColumnResult(name = "comment_count", type = int.class)
},
targetClass = PostTitleWithCommentCount.class
)
}
)
ConstructorResult
注释允许我们指示 Hibernate 使用哪个 DTO 类以及在实例化 DTO 对象时调用哪个构造函数。
请注意,我们使用了@ColumnResult
注释的type
属性来指定comment_count
应该转换为 Java int
。 这是必需的,因为一些 JDBC 驱动程序使用Long
或BigInteger
作为 SQL 聚合函数结果。
这是使用 JPA 调用PostTitleWithCommentCount
命名本机查询的方法:
List<PostTitleWithCommentCount> postTitleAndCommentCountList = entityManager
.createNamedQuery("PostTitleWithCommentCount")
.setMaxResults(POST_RESULT_COUNT)
.getResultList();
而且,我们可以看到返回的PostTitleWithCommentCount
DTO 已正确获取:
assertEquals(POST_RESULT_COUNT, postTitleAndCommentCountList.size());
for (int i = 0; i < POST_RESULT_COUNT; i++) {
PostTitleWithCommentCount postTitleWithCommentCount =
postTitleAndCommentCountList.get(i);
assertEquals(
String.format(
"High-Performance Java Persistence - Chapter %d",
i + 1
),
postTitleWithCommentCount.getPostTitle()
);
assertEquals(COMMENT_COUNT, postTitleWithCommentCount.getCommentCount());
}
有关使用 JPA 和 Hibernate 获取 DTO 投影的最佳方法的更多详细信息,请查看这篇文章。
前面的示例展示了如何将 SQL 聚合结果集映射到 DTO。 但是,如果我们想要返回我们正在计算评论的 JPA 实体怎么办?
为了实现这个目标,我们可以使用entities
属性来定义我们正在获取的Post
实体,并使用@SqlResultSetMapping
注解的classes
属性来映射标量值,在我们的例子中是关联的post_comment
记录的数量:
@NamedNativeQuery(
name = "PostWithCommentCount",
query = """
SELECT
p.id AS "p.id",
p.title AS "p.title",
p.created_on AS "p.created_on",
COUNT(pc.*) AS "comment_count"
FROM post_comment pc
LEFT JOIN post p ON p.id = pc.post_id
GROUP BY p.id, p.title
ORDER BY p.id
""",
resultSetMapping = "PostWithCommentCountMapping"
)
@SqlResultSetMapping(
name = "PostWithCommentCountMapping",
entities = @EntityResult(
entityClass = Post.class,
fields = {
@FieldResult(name = "id", column = "p.id"),
@FieldResult(name = "createdOn", column = "p.created_on"),
@FieldResult(name = "title", column = "p.title"),
}
),
columns = @ColumnResult(
name = "comment_count",
type = int.class
)
)
执行PostWithCommentCount
命名本机查询时:
List<Object[]> postWithCommentCountList = entityManager
.createNamedQuery("PostWithCommentCount")
.setMaxResults(POST_RESULT_COUNT)
.getResultList();
我们将获得Post
实体和commentCount
标量列值:
assertEquals(POST_RESULT_COUNT, postWithCommentCountList.size());
for (int i = 0; i < POST_RESULT_COUNT; i++) {
Post post = (Post) postWithCommentCountList.get(i)[0];
int commentCount = (int) postWithCommentCountList.get(i)[1];
assertTrue(entityManager.contains(post));
assertEquals(i + 1, post.getId().intValue());
assertEquals(
String.format(
"High-Performance Java Persistence - Chapter %d",
i + 1
),
post.getTitle()
);
assertEquals(COMMENT_COUNT, commentCount);
}
@Entity
@SqlResultSetMapping(name="ConnexionQueryBean",
entities={
@EntityResult(entityClass=com.collecteJ.business.bean.ConnexionQueryBean.class, fields={
@FieldResult(name="utilisateurId", column="UTILISATEUR_ID"),
@FieldResult(name="nom", column="NOM"),
@FieldResult(name="prenom", column="PRENOM"),
@FieldResult(name="nomConnexion", column="NOM_CONNEXION"),
@FieldResult(name="codeAgence", column="CODE_AGENCE"),
@FieldResult(name="codeBanque", column="CODE_BANQUE"),
@FieldResult(name="codeDevise", column="CODE_DEVISE"),
@FieldResult(name="codeCollecteur", column="CODE_COLLECTEUR")})
})
public class ConnexionQueryBean implements Serializable {
@Id
private long utilisateurId;
private String codeCollecteur;
private String nom;
private String prenom;
private String nomConnexion;
private String codeAgence;
private String codeBanque;
private String codeDevise;
public ConnexionQueryBean() {
}
public long getUtilisateurId() {
return utilisateurId;
}
public void setUtilisateurId(long utilisateurId) {
this.utilisateurId = utilisateurId;
}
public String getCodeCollecteur() {
return codeCollecteur;
}
public void setCodeCollecteur(String codeCollecteur) {
this.codeCollecteur = codeCollecteur;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public String getPrenom() {
return prenom;
}
public void setPrenom(String prenom) {
this.prenom = prenom;
}
public String getNomConnexion() {
return nomConnexion;
}
public void setNomConnexion(String nomConnexion) {
this.nomConnexion = nomConnexion;
}
public String getCodeAgence() {
return codeAgence;
}
public void setCodeAgence(String codeAgence) {
this.codeAgence = codeAgence;
}
public String getCodeBanque() {
return codeBanque;
}
public void setCodeBanque(String codeBanque) {
this.codeBanque = codeBanque;
}
public String getCodeDevise() {
return codeDevise;
}
public void setCodeDevise(String codeDevise) {
this.codeDevise = codeDevise;
}
@Override
public String toString() {
return "ConnexionQueryBean{" + "utilisateurId=" + utilisateurId + ", codeCollecteur=" + codeCollecteur + ", nom=" + nom + ", prenom=" + prenom + ", nomConnexion=" + nomConnexion + ", codeAgence=" + codeAgence + ", codeBanque=" + codeBanque + ", codeDevise=" + codeDevise + '}';
}
这不是一个真正的实体,因为它不匹配任何数据库表。 但是@Entity
和@Id
注释是 JPA 必须理解映射的。 如果您真的不想在该类中包含@Entity / @Id
,则可以删除@SqlResultSetMapping
注释并将其放在 JPA 可以扫描的任何其他实体中。
您还应该确保您的@ComponentScan
包含相应的包,如果您使用基于 java 的 spring 配置,您应该在META-INF
目录下的persistence.xml/orm.xml
中显式声明您的实体。
这是电话
String connexionQuery = "SELECT u.UTILISATEUR_ID, u.NOM, u.PRENOM, u.NOM_CONNEXION, a.CODE_AGENCE, a.CODE_BANQUE, a.CODE_DEVISE, c.CODE_COLLECTEUR FROM UTILISATEUR u, AGENCE a, COLLECTEUR c "
+ " WHERE (a.CODE_AGENCE = c.CODE_AGENCE AND u.UTILISATEUR_ID = c.UTILISATEUR_ID AND u.NOM_CONNEXION = '"+nomConnextion+"')";
ConnexionQueryBean ConnexionResults = (ConnexionQueryBean) defaultService.getEntityManager().createNativeQuery(connexionQuery,"ConnexionQueryBean").getSingleResult();
System.out.println(ConnexionResults.toString());
我正在使用 Spring、JPA 2.1、Hibernate 5 和 Oracle,我认为 JPA 较低版本可能无法做到这一点,找到更多http://www.thoughts-on-java.org/result-set-mapping-complex-映射/
我有一个略有不同的答案,它只是从 Wildloop 的答案中得出的。
这是我的答案:
常量类:Constants.java
public class Constants {
public final String TESTQUERYRESULT_MAPPING_NAME = "TestQueryResultMapping";
}
结果映射类:TestQueryResult.java
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Entity;
import javax.persistence.EntityResult;
import javax.persistence.FieldResult;
import javax.persistence.Id;
import javax.persistence.SqlResultSetMapping;
@Getter
@Setter
@SqlResultSetMapping(
//name = "TestQueryResultMapping"
name = Constants.TESTQUERYRESULT_MAPPING_NAME
,entities = @EntityResult(
entityClass = TestQueryResult.class
,fields = {
@FieldResult(name = "rowId", column = "row_id")
,@FieldResult(name = "rowName", column = "row_name")
,@FieldResult(name = "value", column = "row_value")
}
)
)
@Entity
public class TestQueryResult {
@Id
private Integer rowId;
private String rowName;
private String value;
}
然后......在我的存储库实现代码中的某个地方:
public class TestQueryRepository {
//... some code here to get the entity manager here
public TestQueryResult getTopMost(Integer rowName) {
//... some code here
String queryString = "... some query string here" + rowName;
TestQueryResult testQueryResult = null;
//this.entityManager.createNativeQuery(queryString ,"TestQueryResultMapping").getResultList();
List<TestQueryResult> results = this.entityManager.createNativeQuery(queryString ,Constants.TESTQUERYRESULT_MAPPING_NAME).getResultList();
if (results != null && !results.isEmpty()) {
testQueryResult = results.get(0);
}
return testQueryResult;
}
}
...然后中提琴! 我得到了一些结果:D!
干杯,
阿塔尼斯·泽拉图
QLRM 可能是一个替代方案: http ://simasch.github.io/qlrm/
它与特定的 JPA 实现无关,也适用于 JDBC。
我最近整理了一个快速的概念证明,它对我自己和另一位开发人员都非常有效。
使用本机查询并使用 SqlResultSetMapping 的 Spring 引导端点,这里是代码片段。
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.metrics.annotation.Timed;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
@RestController
@RequestMapping(value = "/rest/yum-query", produces = APPLICATION_JSON_VALUE)
@Api(tags = {"notification"})
@Timed(extraTags = {"controller", "YumController"})
public class YumController {
private final YumService yumService;
@Autowired
public YumController(YumService yumService) {
this.yumService = yumService;
}
@GetMapping(produces = APPLICATION_JSON_VALUE)
public List<ApprovedApplicationsDTO> findApprovedApplications() {
return yumService.findApprovedApplications();
}
}
添加我的服务
import au.edu.qld.qcaa.sate.serviceaara.domain.repository.YumRepositoryCustom;
import au.edu.qld.qcaa.sate.serviceaara.dto.yum.ApprovedApplicationsDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Slf4j
@Service
public class YumService {
private YumRepositoryCustom yumRepositoryCustom;
@Autowired
public YumService(YumRepositoryCustom yumRepositoryCustom) {
this.yumRepositoryCustom = yumRepositoryCustom;
}
public List<ApprovedApplicationsDTO> findApprovedApplications() {
return yumRepositoryCustom.findApprovedApplicationsNativeQuery();
}
}
为本地查询设置一个新的查询结果类以映射到
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.ColumnResult;
import javax.persistence.ConstructorResult;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.SqlResultSetMapping;
import java.math.BigInteger;
@MappedSuperclass
@SqlResultSetMapping(name = "ApprovedApplicationQueryResultBean",
classes = {
@ConstructorResult(
targetClass = ApprovedApplicationQueryResultBean.class,
columns = {
@ColumnResult(name = "application_id", type = BigInteger.class),
@ColumnResult(name = "application_type", type = String.class),
@ColumnResult(name = "assessment_identifier", type = String.class),
@ColumnResult(name = "aara_code", type = String.class),
@ColumnResult(name = "aara_code_child", type = String.class),
@ColumnResult(name = "completion_year", type = Integer.class),
@ColumnResult(name = "reason", type = String.class),
@ColumnResult(name = "code", type = String.class),
@ColumnResult(name = "long_description", type = String.class),
@ColumnResult(name = "identified_condition", type = String.class),
@ColumnResult(name = "other", type = String.class),
@ColumnResult(name = "decision_code", type = String.class),
}
)
})
@NoArgsConstructor
@AllArgsConstructor
@Data
public class ApprovedApplicationQueryResultBean {
@Id
private BigInteger applicationId;
private String applicationType;
private String assessmentIdentifier;
private String aaraCode;
private String aaraCodeChild;
private Integer completionYear;
private String reason;
private String code;
private String longDescription;
private String identifiedCondition;
private String other;
private String decisionCode;
}
创建一个新的存储库接口和实现类来调用查询
import au.edu.qld.qcaa.sate.serviceaara.dto.yum.ApprovedApplicationsDTO;
import java.util.List;
public interface YumRepositoryCustom {
List<ApprovedApplicationsDTO> findApprovedApplicationsNativeQuery();
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
@Slf4j
public class YumRepositoryCustomImpl implements YumRepositoryCustom {
@PersistenceContext
private EntityManager em;
@Override
public List<ApprovedApplicationsDTO> findApprovedApplicationsNativeQuery() {
StringBuilder q = new StringBuilder();
q.append("select distinct a4.application_id, a4.application_type, a3.assessment_identifier, ");
q.append("a3.aara_code, ad.aara_code_child, a3.completion_year, c.reason, rd.code, rd.long_description, ic.identified_condition, ic.other, ad2.decision_code ");
q.append("from category c ");
q.append("left join application a4 on a4.application_id = c.application_id ");
q.append("left join arrangement a3 on a3.application_id = a4.application_id ");
q.append("left join arrangement_detail ad on a3.arrangement_id = ad.arrangement_id ");
q.append("left join identified_condition ic on ic.category_id = c.category_id ");
q.append("left join reference_data rd on rd.code = c.reason ");
q.append("left join arrangement_decision ad2 on ad2.arrangement_id = a3.arrangement_id ");
q.append("left JOIN (SELECT max(ad3.arrangement_decision_id) as theid ");
q.append("FROM arrangement_decision ad3 ");
q.append("GROUP BY ad3.arrangement_id) b on ad2.arrangement_decision_id = b.theid ");
q.append("where a4.application_type = ?1 and a3.completion_year = ?2 ");
q.append("and a4.is_active = true and a3.is_active = true and ic.is_active = true and c.is_active = true ");
q.append("order by 1 ");
Query query = em.createNativeQuery(q.toString(), "ApprovedApplicationQueryResultBean");
query.setParameter(1, ApplicationConstants.APPLICATION_TYPE_AARA);
query.setParameter(2, Calendar.getInstance().get(Calendar.YEAR));
List<ApprovedApplicationQueryResultBean> entityResults = query.getResultList();
return entityResults.stream().map(entity -> {
return mapToDTO(entity);
}).collect(Collectors.toList());
}
private ApprovedApplicationsDTO mapToDTO(ApprovedApplicationQueryResultBean entity) {
return ApprovedApplicationsDTO.builder()
.applicationId(entity.getApplicationId())
.applicationType(entity.getApplicationType())
.aaraCode(entity.getAaraCode())
.aaraCodeChild(entity.getAaraCodeChild())
.completionYear(entity.getCompletionYear())
.reason(entity.getReason())
.code(entity.getCode())
.longDescription(entity.getLongDescription())
.identifiedCondition(entity.getIdentifiedCondition())
.other(entity.getOther())
.decisionCode(entity.getDecisionCode())
.build();
}
}
添加我的端点响应 DTO
import lombok.Builder;
import lombok.Data;
import java.math.BigInteger;
@Data
@Builder
public class ApprovedApplicationsDTO {
private BigInteger applicationId;
private String applicationType;
private String assessmentIdentifier;
private String aaraCode;
private String aaraCodeChild;
private Integer completionYear;
private String reason;
private String code;
private String longDescription;
private String identifiedCondition;
private String other;
private String decisionCode;
}
Then hit my endpoint via postman or curl or which ever tool you wish to use:
http://localhost:10050/rest/yum-query
该解决方案独立于 JPA 实现。 一旦您将本机查询的结果收集为
List<Object[]> = em.createNativeQueryBar(QUERY, "foo").getResultList();
如果您需要将每个 List 元素映射到 Person 例如
Class Person { String name; Int age; }
其中列表元素 [0] 是名称,元素 [1] 是年龄。
您可以使用ObjectMapper将 Object[] 转换为 Person 。 您需要在类上添加 @JsonFormat 注释。
@JsonFormat(shape = JsonFormat.Shape.ARRAY)
Class Person { String name; Int age; }
并将 Object[] 转换为 Person 为
ObjectMapper mapper = new ObjectMapper();
JSONArray jsonArray = new JSONArray(Arrays.asList(attributes)).toString();
Person person = mapper.readValue(jsonArray, Person.class);
@MappedSuperclass
@SqlResultSetMapping(name="foo",
classes = {
@ConstructorResult(
targetClass = Bar.class,
columns = {
@ColumnResult(name = "barId", type = Long.class),
@ColumnResult(name = "barName", type = String.class),
@ColumnResult(name = "barTotal", type = Long.class)
})
})
你可以这样做,但这不是很推荐,因为它不是很舒服。 你可以像下面那样做。
Query query = em.createNativeQueryBar(QUERY);
... set some parameters ...
List<Object[]> result = query.getResultList();
List<Bar> list = result.stream().map(
objects -> {
Bar bar = new Bar();
bar.setBarId(Long.parseLong(objects[0].toString()));
bar.setBarName(objects[1].toString());
bar.setBarTotal(Long.parseLong(objects[2].toString()));
...
return bar;
}
).collect(Collectors.toList());
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.