将NativeQuery结果映射到POJO

时间:2014-08-07 17:48:44

标签: java hibernate jpa pojo

我正在尝试使用带@ConstructorResult的@SqlResultSetMapping将Native查询的结果映射到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]

11 个答案:

答案 0 :(得分:29)

@SqlResultSetMapping注释不应放在POJO 上。把它放在(任何)@Entity课堂上。 “Unknown SqlResultSetMapping [foo]”告诉您,JPA提供程序在名称'foo'下没有看到任何映射。请参阅我的另一个答案以获取正确的示例

答案 1 :(得分:10)

简短的工作示例:

  • 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
    
    }
    

答案 2 :(得分:5)

我能够这样做:

Session session = em().unwrap(Session.class);
SQLQuery q = session.createSQLQuery("YOUR SQL HERE");
q.setResultTransformer( Transformers.aliasToBean( MyNotMappedPojoClassHere.class) );
List<MyNotMappedPojoClassHere> postList = q.list();

答案 3 :(得分:3)

@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自动关联您的映射。

答案 4 :(得分:2)

@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的弹簧配置,则应在persistence.xml/orm.xml下的META-INF明确声明您的实体。目录

这是电话

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-mappings/

答案 5 :(得分:0)

QLRM可以替代:http://simasch.github.io/qlrm/

它与特定的JPA实现无关,也适用于JDBC。

答案 6 :(得分:0)

我有一个略有不同的答案,只是从wildloop的答案中得出的。
这是我的答案:

常量类:Constants.java

select
  CountryRegionCode]
  , [StateProvinceCode]
  , COUNT(PSP.StateProvinceID) as [No. of Stores]
from [Sales].[Store] as SS
  inner join [Person].[BusinessEntityAddress] as PBEA on SS.BusinessEntityID = PBEA.BusinessEntityID
  inner join [Person].[Address] as PA on PBEA.AddressID = PA.AddressID
  inner join [Person].[StateProvince] as PSP on PA.StateProvinceID = PSP.StateProvinceID
group by 
  CountryRegionCode
  ,StateProvinceCode
having
  count(PSP.StateProvinceID) = 
   (select min(a.cnt)
     from (select count(PSP.StateProvinceID) as cnt from [Sales].[Store] as SS2
       inner join [Person].[BusinessEntityAddress] as PBEA2 on SS2.BusinessEntityID = PBEA2.BusinessEntityID
       inner join [Person].[Address] as PA2 on PBEA2.AddressID = PA2.AddressID
       inner join [Person].[StateProvince] as PSP2 on pa2.StateProvinceID = PSP2.StateProvinceID
  group by 
    CountryRegionCode) as a)
  order by CountryRegionCode

结果映射类:TestQueryResult.java

public class Constants {
    public final String TESTQUERYRESULT_MAPPING_NAME = "TestQueryResultMapping";
}

然后...在我的存储库实现代码中的某个地方:

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;

}


...然后中提琴!我得到了一些结果:D!

干杯,
Artanis Zeratul

答案 7 :(得分:0)

这是一个非常常见的问题,因此此答案基于我在博客上写的this article

域模型

让我们考虑我们的数据库中有以下postpost_comment表:

JPA SqlResultSetMapping <code>post</code> and <code>post_comment</code> tables

JPA 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

接下来,我们将了解这三个映射选项的工作方式,以及需要使用它们的用例。

JPA SqlResultSetMapping-EntityResult

通过EntityResult选项,您可以将JDBC ResultSet列映射到一个或多个JPA实体。

假设我们要获取前5个Post实体以及与给定PostComment模式匹配的所有关联title实体。

正如我在this article中所解释的,我们可以使用DENSE_RANK SQL Window Function来了解如何过滤postpost_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实体,因此我们需要配置entities批注的@SqlResultSetMapping属性,如下所示:

@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,我们可以像这样获取PostPostComment实体:

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()
    );
}

通过SQL存储过程获取JPA实体时,@EntityResult也很有用。查看this article了解更多详细信息。

JPA SqlResultSetMapping-ConstructorResult

让我们假设要执行一个聚合查询,该查询对每个post_coment的{​​{1}}条记录进行计数并返回post post以进行报告。我们可以使用以下SQL查询来实现此目标:

title

我们还希望在以下DTO中封装帖子标题和评论数:

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

要将上述SQL查询的结果集映射到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; } } DTO,我们可以使用PostTitleWithCommentCount批注的classes属性,如下所示:

@SqlResultSetMapping

@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 ) } ) 注释使我们可以指示Hibernate在实例化DTO对象时使用哪种DTO类以及要调用的构造函数。

请注意,我们使用了ConstructorResult批注的type属性来指定将@ColumnResult强制转换为Java comment_count。这是必需的,因为某些JDBC驱动程序对SQL聚合函数结果使用intLong

这是使用JPA调用名为BigInteger的本机查询的方法:

PostTitleWithCommentCount

而且,我们可以看到返回的List<PostTitleWithCommentCount> postTitleAndCommentCountList = entityManager .createNamedQuery("PostTitleWithCommentCount") .setMaxResults(POST_RESULT_COUNT) .getResultList(); DTO已正确获取:

assertEquals(POST_RESULT_COUNT,postTitleAndCommentCountList.size());

PostTitleWithCommentCount

有关使用JPA和Hibernate获取DTO投影的最佳方法的更多详细信息,请查看this article

JPA SqlResultSetMapping-ColumnResult

前面的示例显示了如何将SQL聚合结果集映射到DTO。但是,如果我们想返回要为其计数注释的JPA实体怎么办?

要实现此目标,我们可以使用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()); } 属性定义要获取的entities实体,并使用Post批注的classes属性映射标量值,在我们的例子中是关联的@SqlResultSetMapping条记录的数量:

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

答案 8 :(得分:0)

我最近整理了一个快速的概念证明,对我自己和另一位开发人员都非常有效。

使用本机查询并利用SqlResultSetMapping的Spring引导端点,这是代码段。

if(snapshot.hasData){
   if (snapshot.data.docs.length != 0) {
        return ListView.builder();
      } else {
        return Text("EMPTY DOCUMENTS");
      } 
}

添加我的服务

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;

}

添加我的端点响应DTO

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();
    }

}

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;

}

答案 9 :(得分:-1)

此解决方案独立于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);

答案 10 :(得分:-1)

@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());