将从 Hibernate Native Query 返回的值映射到模型

Posted

技术标签:

【中文标题】将从 Hibernate Native Query 返回的值映射到模型【英文标题】:Map values returned from Hibernate Native Query to a model 【发布时间】:2020-05-22 17:57:58 【问题描述】:

我对 Hibernate 很陌生。我将它与我的 Spring Boot 项目一起使用。由于涉及复杂的连接,我想编写本机 SQL 查询。 在执行查询时,返回的值是列表的形式,没有简单的方法将它们映射到 HashMap。

现在我正在使用以下方法,该方法有效,但在很大程度上取决于从查询列表返回的值的顺序。

有没有简单有效的方法来映射这个结果。

@Transactional

public List<Object> getAllUsers() 

    Session currentSession = entityManager.unwrap(Session.class);


    String queryString = "select ts.id as id, ts.remarks, concat(s.first_name, ' ',s.last_name) as studentName,\n" + 
            "ts.start_date as startDate, ts.end_date as endDate, ts.status,\n" + 
            "ts.created_at as createdAt, ts.created_by as createdBy, \n" + 
            "ts.updated_at as updatedAt, ts.updated_by as updatedBy\n" + 
            "from TRN_STATUS ts join types lt on ts.type_id = lt.id join users s on s.id = ts.id \n" + 
            "join category ct on ts.cat_id = ct.id\n" + 
            "where ts.tenant_id = 1";
    NativeQuery query = currentSession.createNativeQuery(queryString);

    List<Object> result = (List<Object>) query.getResultList();

    currentSession.close();
    return result;


服务

public List<Map<String, Object>> getCount(Optional<String> userId, String userType, String limit, String offset) 

    List<Object> users= userDAO. getAllUsers();
    List<Map<String, Object>> userList = new ArrayList<>();
    Iterator userItr = users.iterator();
    ObjectMapper userMapper = new ObjectMapper();
    Map<String, Object> map;
    UserModel obj = new UserModel();
    while(userItr.hasNext()) 
        Object[] resobj = (Object[]) leaveItr.next();
        obj.setId(String.valueOf(resobj[0]));
        obj.setStartDate(String.valueOf(resobj[1]));
        obj.setEndDate(String.valueOf(resobj[2]));
        obj.setDescription(String.valueOf(resobj[3]));
        obj.setLeaveType(String.valueOf(resobj[4]));
        obj.setCategoryId(String.valueOf(resobj[5]));
        obj.setCategoryName(String.valueOf(resobj[6]));
        obj.setStatus(String.valueOf(resobj[7]));
        obj.setDesignation(String.valueOf(resobj[8]));
        obj.setActionBy(String.valueOf(resobj[9]));
        obj.setStudentName(String.valueOf(resobj[10]));
        obj.setImgUrl(String.valueOf(resobj[11]));

        map = userMapper.convertValue(obj, Map.class);
        userList.add(map);

        logger.info("Value displayed was: "+ map);
    
return userList;

用户模型

import lombok.Data;

public @Data class UserModel 

private String id;
private String startDate;
private String endDate;
private String description;
private String leaveType;
private String categoryId;
private String categoryName;
private String status;
private String designation;
private String actionBy;
private String studentName;
private String imgUrl;
private String createdDate; 
private String hostelName;
private String blockName;
private String roomName;

【问题讨论】:

【参考方案1】:

有一种简单有效的方法来映射此结果

与其创建一个方法,然后将所需的返回值映射到一个 bean 类,只需创建一个 Entity 类,其中包含与查询中返回的字段映射的所有字段。

使用@NamedNativeQuery 提供查询,使用@SqlResultSetMapping 映射执行查询后要返回的字段。

例如

@NamedNativeQuery(
            name = "getTenders",
            query = "SELECT t.id, t.created_at, CONCAT(u.first_name, ' ' , u.last_name) as created_by, t.modified_at, CONCAT(u2.first_name, ' ' , u2.last_name) as modified_by, t.tenders_abbreviation, t.tenders_full_name FROM abc.tenders v\n" + 
                    "LEFT JOIN abc.users u on u.id = v.created_by LEFT JOIN rbac.users u2 on u2.id = v.modified_by",
            resultSetMapping = "tendersMappings"
            )

@SqlResultSetMapping(name = "tendersMappings", entities = 
        @EntityResult(entityClass = TendersEntity.class, fields = 
                @FieldResult(name = "id", column = "id"),
                @FieldResult(name = "created_at", column = "created_at"),
                @FieldResult(name = "modified_at", column = "modified_at"),
                @FieldResult(name = "tenders_abbreviation", column = "tenders_abbreviation"),
                @FieldResult(name = "tenders_full_name", column = "tenders_full_name"),
                @FieldResult(name = "created_by", column = "created_by"),
                @FieldResult(name = "modified_by", column = "modified_by")
                ) 
        )
@Entity
@Table(name = "tenders", schema = "abc")
public class TendersEntity 


    private static final long serialVersionUID = 1L;

    @Id
    private Integer id;

    @Column(name = "created_at")
    private String created_at;

    @Column(name = "created_by")
    private String created_by;

    @Column(name = "modified_at")
    private String modified_at;

    @Column(name = "modified_by")
    private String modified_by;

    @Column(name = "tenders_abbreviation")
    private String tenders_abbreviation;

    @Column(name = "tenders_full_name")
    private String tenders_full_name;


    public TendersEntity() 

    // setters and getters

//DAO类

@Repository
@Transactional
public class TendersDaoImpl implements TendersDao 

    @Autowired
    EntityManager manager;

    @Override
    public List<TendersEntity> getVendors() 
        List<TendersEntity> dataList = new ArrayList<>();
        Query query = manager.createNamedQuery("getTenders");
        try 
            dataList.addAll(query.getResultList());
         catch (Exception ex) 
            …….// exception code
        
        return dataList;
    

【讨论】:

你有 @Table(name = “tenders”, schema = “abc”) 即有一个表。但 sql 是多个表的连接。映射是如何发生的? 这里的招标是基表,映射是根据查询返回的数据完成的【参考方案2】:

您可以为此使用 SQL 转换器:

使用原生 sql 返回非实体 bean 或 Map 通常比基本的 Object[] 更有用。使用结果转换器是可能的。

示例:

List resultWithAliasedBean = s.createSQLQuery(
  "SELECT st.name as studentName, co.description as courseDescription " +
  "FROM Enrolment e " +
  "INNER JOIN Student st on e.studentId=st.studentId " +
  "INNER JOIN Course co on e.courseCode=co.courseCode")
  .addScalar("studentName")
  .addScalar("courseDescription")
  .setResultTransformer( Transformers.aliasToBean(StudentDTO.class))
  .list();

StudentDTO dto =(StudentDTO) resultWithAliasedBean.get(0);

参考: https://docs.jboss.org/hibernate/core/3.3/reference/en/html/querysql.html#d0e13904

【讨论】:

StudentDTO的内容是什么? 在你的情况下,它将是 UserModel。

以上是关于将从 Hibernate Native Query 返回的值映射到模型的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate中的query.setFirstResult(),query.setMaxResults();

hibernate里‘query’和‘ Criteria’分别啥时候用

Hibernate的升级&&Query用法

Hibernate学习笔记---Query接口

hibernate的Criteria Query(转)

有啥方法可以将从 APISAUCE API 收到的响应存储到异步存储中作为缓存并在 React Native 的平面列表中显示