ChatGPT解决这个技术问题 Extra ChatGPT

JPA:如何将原生查询结果集转换为 POJO 类集合

我在我的项目中使用 JPA。

我遇到了一个查询,其中我需要对五个表进行连接操作。所以我创建了一个返回五个字段的本机查询。

现在我想将结果对象转换为包含相同五个字符串的 java POJO 类。

JPA 中有没有办法直接将该结果转换为 POJO 对象列表?

我来到以下解决方案..

@NamedNativeQueries({  
    @NamedNativeQuery(  
        name = "nativeSQL",  
        query = "SELECT * FROM Actors",  
        resultClass = db.Actor.class),  
    @NamedNativeQuery(  
        name = "nativeSQL2",  
        query = "SELECT COUNT(*) FROM Actors",  
        resultClass = XXXXX) // <--------------- problem  
})  

现在在 resultClass 中,我们是否需要提供一个实际 JPA 实体的类?或者我们可以将它转换为任何包含相同列名的 JAVA POJO 类?

检查这个答案。它有完整的答案:stackoverflow.com/a/50365522/3073945
他正在使用 jpa,而不是 spring

E
Edwin Dalorzo

我找到了几个解决方案。

使用映射实体 (JPA 2.0)

使用 JPA 2.0 无法将本机查询映射到 POJO,只能使用实体来完成。

例如:

Query query = em.createNativeQuery("SELECT name,age FROM jedi_table", Jedi.class);
@SuppressWarnings("unchecked")
List<Jedi> items = (List<Jedi>) query.getResultList();

但在这种情况下,Jedi 必须是映射的实体类。

在这里避免未经检查的警告的另一种方法是使用命名的本机查询。因此,如果我们在实体中声明本机查询

@NamedNativeQuery(
 name="jedisQry", 
 query = "SELECT name,age FROM jedis_table", 
 resultClass = Jedi.class)

然后,我们可以简单地做:

TypedQuery<Jedi> query = em.createNamedQuery("jedisQry", Jedi.class);
List<Jedi> items = query.getResultList();

这更安全,但我们仍然被限制使用映射实体。

手动映射

我尝试了一下(在 JPA 2.1 到来之前)的一个解决方案是使用一点反射对 POJO 构造函数进行映射。

public static <T> T map(Class<T> type, Object[] tuple){
   List<Class<?>> tupleTypes = new ArrayList<>();
   for(Object field : tuple){
      tupleTypes.add(field.getClass());
   }
   try {
      Constructor<T> ctor = type.getConstructor(tupleTypes.toArray(new Class<?>[tuple.length]));
      return ctor.newInstance(tuple);
   } catch (Exception e) {
      throw new RuntimeException(e);
   }
}

此方法基本上采用元组数组(由本机查询返回)并通过查找具有相同数量的字段和相同类型的构造函数将其映射到提供的 POJO 类。

然后我们可以使用方便的方法,例如:

public static <T> List<T> map(Class<T> type, List<Object[]> records){
   List<T> result = new LinkedList<>();
   for(Object[] record : records){
      result.add(map(type, record));
   }
   return result;
}

public static <T> List<T> getResultList(Query query, Class<T> type){
  @SuppressWarnings("unchecked")
  List<Object[]> records = query.getResultList();
  return map(type, records);
}

我们可以简单地使用这种技术,如下所示:

Query query = em.createNativeQuery("SELECT name,age FROM jedis_table");
List<Jedi> jedis = getResultList(query, Jedi.class);

带有@SqlResultSetMapping 的 JPA 2.1

随着 JPA 2.1 的到来,我们可以使用 @SqlResultSetMapping 注解来解决这个问题。

我们需要在实体的某处声明一个结果集映射:

@SqlResultSetMapping(name="JediResult", classes = {
    @ConstructorResult(targetClass = Jedi.class, 
    columns = {@ColumnResult(name="name"), @ColumnResult(name="age")})
})

然后我们简单地做:

Query query = em.createNativeQuery("SELECT name,age FROM jedis_table", "JediResult");
@SuppressWarnings("unchecked")
List<Jedi> samples = query.getResultList();

当然,在这种情况下,Jedi 不必是映射实体。它可以是一个普通的 POJO。

使用 XML 映射

我是发现在我的实体中添加所有这些 @SqlResultSetMapping 的人之一,我特别不喜欢实体中命名查询的定义,因此我可以在 META-INF/orm.xml 文件中执行所有这些操作:

<named-native-query name="GetAllJedi" result-set-mapping="JediMapping">
    <query>SELECT name,age FROM jedi_table</query>
</named-native-query>

<sql-result-set-mapping name="JediMapping">
        <constructor-result target-class="org.answer.model.Jedi">
            <column name="name" class="java.lang.String"/>
            <column name="age" class="java.lang.Integer"/>
        </constructor-result>
    </sql-result-set-mapping>

这些就是我所知道的所有解决方案。如果我们可以使用 JPA 2.1,最后两个是理想的方式。


旁注:我刚刚使用了具有 JPA2.1 依赖项的 JPA 2.0 方法,但它失败了。所以可能这不是向下兼容的......
“实体中的某个地方”是什么意思?我的 Pojo 不是 JPA 实体我不能在我的 POJO 中声明 @SqlResultSetMapping 吗?我对 JPA 2.1 解决方案感兴趣。请准确一点。
@Alboz @SqlResultSetMapping 必须放在一个实体中,因为这就是 JPA 将从中读取元数据的地方。您不能指望 JPA 检查您的 POJO。您放置映射的实体是无关紧要的,也许是与您的 POJO 结果更相关的实体。或者,映射可以用 XML 表示,以避免与完全不相关的实体耦合。
构造函数结果是否可以使用具有嵌套类的类?
如果将 JPA 2.1 与 @SqlResultSetMapping 一起使用,可能值得注意的是 Jedi 类将需要一个全参数构造函数,并且 @ColumnResult 注释可能需要将 type 属性添加到可能不是隐式的转换(我需要为某些列添加 type = ZonedDateTime.class)。
D
Denis Tulskiy

JPA 提供了一个 SqlResultSetMapping,允许您将本地查询的任何返回映射到实体 或自定义类

EDIT JPA 1.0 不允许映射到非实体类。仅在 JPA 2.1 中添加了 ConstructorResult 以将返回值映射到 java 类。

此外,对于 OP 的计数问题,使用单个 ColumnResult 定义结果集映射就足够了


谢谢回复。在这里,我们将结果与带有“@EntityResult”和“@FieldResult”注释的 java 实体类的实体映射。没关系。但在这里我需要更清楚。我们与结果映射的类是否必须是 JPA 实体类?或者我们可以使用一个简单的 POJO 类,它不是一个实体购买,它具有所有必需的变量作为结果集中的列。
@GunjanShah:最好的了解方法是试一试:) 此外,实体只是同一个 pojo,只是带有一些注释。只要你不试图坚持它,它就会一直保持下去。
当我尝试这个时,我收到一个错误,即该类不是已知实体。我最终使用了这种方法 stackoverflow.com/questions/5024533/… 而不是尝试使用本机查询。
@EdwinDalorzo:这对 jpa 1.0 来说是正确的。在 jpa 2.1 中,他们将 ConstructorResult 添加为 SqlResultSetMapping 的参数之一,允许使用在构造函数中设置的所有字段的 pojo。我会更新答案。
我看到另一个苦涩的事实: ConstructorResult 可以映射到 POJO .. 但是 ConstructorResult 本身必须在 Entity 类中,所以 Entity 你无法避免......因此更大的硬事实:你需要一些不关心的结果到主键 - 你仍然必须在实体中有@Id ...荒谬吗?
D
DavidS

是的,使用 JPA 2.1 很容易。你有非常有用的注释。他们简化了你的生活。

首先声明您的本机查询,然后声明您的结果集映射(它定义了数据库返回的数据到您的 POJO 的映射)。编写您的 POJO 类以供参考(为简洁起见,此处不包括在内)。最后但同样重要的是:在 DAO(例如)中创建一个方法来调用查询。这在 dropwizard (1.0.0) 应用程序中对我有用。

首先在实体类中声明一个原生查询:

@NamedNativeQuery (
name = "domain.io.MyClass.myQuery",
query = "Select a.colA, a.colB from Table a",
resultSetMapping = "mappinMyNativeQuery")   // must be the same name as in the SqlResultSetMapping declaration

您可以在下面添加结果集映射声明:

@SqlResultSetMapping(
name = "mapppinNativeQuery",  // same as resultSetMapping above in NativeQuery
   classes = {
      @ConstructorResult( 
          targetClass = domain.io.MyMapping.class,
          columns = {
               @ColumnResult( name = "colA", type = Long.class),  
               @ColumnResult( name = "colB", type = String.class)
          }
      )
   } 
)

稍后在 DAO 中,您可以将查询称为

public List<domain.io.MyMapping> findAll() {
        return (namedQuery("domain.io.MyClass.myQuery").list());
    }

而已。


不错的答案,但我认为您在第一个 @ColumnResult 注释之后错过了一个括号。
代码中有错误,但很容易纠正。例如:“resulSetMapping =”应该是“resultSetMapping =”
我看到了另一个苦涩的事实:NamedNativeQuery 和 SqlResultSetMapping 必须在 @Entity 类中
K
Kohei TAMURA

如果您使用 Spring-jpa,这是对答案和此问题的补充。如有不足请指正。根据我实际满足的需求,我主要使用了三种方法来实现“将结果Object[]映射到pojo”:

JPA 内置方法就足够了。 JPA 内置方法是不够的,但是一个带有实体的自定义 sql 就足够了。前2个失败了,我不得不使用nativeQuery。以下是示例。预期的pojo: public class Antistealingdto { private String secretKey;私人整数成功率; // GETTER 和 SETTER public Antistealingdto(String secretKey, Integer successRate) { this.secretKey = secretKey; this.successRate = 成功率; } }

方法一:将pojo改成接口:

public interface Antistealingdto {
    String getSecretKey();
    Integer getSuccessRate();
}

和存储库:

interface AntiStealingRepository extends CrudRepository<Antistealing, Long> {
    Antistealingdto findById(Long id);
}

方法2:存储库:

@Query("select new AntistealingDTO(secretKey, successRate) from Antistealing where ....")
Antistealing whatevernamehere(conditions);

注意:POJO 构造函数的参数顺序在 POJO 定义和 sql 中必须一致。

方法 3:使用 Entity 中的 @SqlResultSetMapping@NamedNativeQuery 作为 Edwin Dalorzo 回答中的示例。

前两种方法将调用许多中间处理程序,例如自定义转换器。例如,AntiStealing 定义了一个 secretKey,在它被持久化之前,会插入一个转换器来对其进行加密。这将导致前 2 个方法返回转换后的 secretKey,这不是我想要的。虽然方法 3 会克服转换器,但返回的 secretKey 将与存储的相同(加密的)。


方法 1 实际上不需要 Spring,并且可以与纯 Hibernate 一起使用。
@MartinVysny 是的,M1 是 JPQL。任何实现 JPQL 的项目都应该支持它。这样一来,也许M2也得到了广泛的支持?
z
zawhtut

可以执行展开过程以将结果分配给非实体(即 Beans/POJO)。程序如下。

List<JobDTO> dtoList = entityManager.createNativeQuery(sql)
        .setParameter("userId", userId)
        .unwrap(org.hibernate.Query.class).setResultTransformer(Transformers.aliasToBean(JobDTO.class)).list();

该用法用于 JPA-Hibernate 实现。


请注意,JobDTO 应该具有默认构造函数。或者您可以基于 AliasToBeanResultTransformer 实现来实现自己的转换器。
为什么要设置参数?
org.hibernate.Query.class).setResultTransformer 显示已弃用。
T
Thanthu

最简单的方法是使用 so 投影。它可以将查询结果直接映射到接口,比使用SqlResultSetMapping更容易实现。

一个例子如下所示:

@Repository
public interface PeopleRepository extends JpaRepository<People, Long> {

    @Query(value = "SELECT p.name AS name, COUNT(dp.people_id) AS count " +
        "FROM people p INNER JOIN dream_people dp " +
        "ON p.id = dp.people_id " +
        "WHERE p.user_id = :userId " +
        "GROUP BY dp.people_id " +
        "ORDER BY p.name", nativeQuery = true)
    List<PeopleDTO> findByPeopleAndCountByUserId(@Param("userId") Long userId);

    @Query(value = "SELECT p.name AS name, COUNT(dp.people_id) AS count " +
        "FROM people p INNER JOIN dream_people dp " +
        "ON p.id = dp.people_id " +
        "WHERE p.user_id = :userId " +
        "GROUP BY dp.people_id " +
        "ORDER BY p.name", nativeQuery = true)
    Page<PeopleDTO> findByPeopleAndCountByUserId(@Param("userId") Long userId, Pageable pageable);

}



// Interface to which result is projected
public interface PeopleDTO {

    String getName();

    Long getCount();

}

投影接口中的字段必须与该实体中的字段匹配。否则字段映射可能会中断。

此外,如果您使用 SELECT table.column 表示法,请始终定义与实体名称匹配的别名,如示例所示。


本机查询和预测不能很好地结合在一起。
我无法让字段映射正常工作 - 大多数值一直返回为 null
Y
Yaswanth raju Vysyaraju

在休眠中,您可以使用此代码轻松映射您的本机查询。

private List < Map < String, Object >> getNativeQueryResultInMap() {
String mapQueryStr = "SELECT * FROM AB_SERVICE three ";
Query query = em.createNativeQuery(mapQueryStr);
NativeQueryImpl nativeQuery = (NativeQueryImpl) query;
nativeQuery.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
List < Map < String, Object >> result = query.getResultList();
for (Map map: result) {
    System.out.println("after request  ::: " + map);
}
return result;}

这是一个非常好的和有用的解决方案。这个对我有用。使用这个 List < Map < String, Object >> 结果我可以做任何事情。我可以在 POJO 中设置值或转换为 JSON 或任何东西。
h
hrishikeshp19

首先声明以下注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface NativeQueryResultEntity {
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NativeQueryResultColumn {
    int index();
}

然后注释您的 POJO,如下所示:

@NativeQueryResultEntity
public class ClassX {
    @NativeQueryResultColumn(index=0)
    private String a;

    @NativeQueryResultColumn(index=1)
    private String b;
}

然后编写注解处理器:

public class NativeQueryResultsMapper {

    private static Logger log = LoggerFactory.getLogger(NativeQueryResultsMapper.class);

    public static <T> List<T> map(List<Object[]> objectArrayList, Class<T> genericType) {
        List<T> ret = new ArrayList<T>();
        List<Field> mappingFields = getNativeQueryResultColumnAnnotatedFields(genericType);
        try {
            for (Object[] objectArr : objectArrayList) {
                T t = genericType.newInstance();
                for (int i = 0; i < objectArr.length; i++) {
                    BeanUtils.setProperty(t, mappingFields.get(i).getName(), objectArr[i]);
                }
                ret.add(t);
            }
        } catch (InstantiationException ie) {
            log.debug("Cannot instantiate: ", ie);
            ret.clear();
        } catch (IllegalAccessException iae) {
            log.debug("Illegal access: ", iae);
            ret.clear();
        } catch (InvocationTargetException ite) {
            log.debug("Cannot invoke method: ", ite);
            ret.clear();
        }
        return ret;
    }

    // Get ordered list of fields
    private static <T> List<Field> getNativeQueryResultColumnAnnotatedFields(Class<T> genericType) {
        Field[] fields = genericType.getDeclaredFields();
        List<Field> orderedFields = Arrays.asList(new Field[fields.length]);
        for (int i = 0; i < fields.length; i++) {
            if (fields[i].isAnnotationPresent(NativeQueryResultColumn.class)) {
                NativeQueryResultColumn nqrc = fields[i].getAnnotation(NativeQueryResultColumn.class);
                orderedFields.set(nqrc.index(), fields[i]);
            }
        }
        return orderedFields;
    }
}

使用上述框架如下:

String sql = "select a,b from x order by a";
Query q = entityManager.createNativeQuery(sql);

List<ClassX> results = NativeQueryResultsMapper.map(q.getResultList(), ClassX.class);

BeanUtils 在哪个包中?
R
Rubens

使用休眠:

@Transactional(readOnly=true)
public void accessUser() {
EntityManager em = repo.getEntityManager();
    org.hibernate.Session session = em.unwrap(org.hibernate.Session.class);
    org.hibernate.SQLQuery q = (org.hibernate.SQLQuery) session.createSQLQuery("SELECT u.username, u.name, u.email, 'blabla' as passe, login_type as loginType FROM users u").addScalar("username", StringType.INSTANCE).addScalar("name", StringType.INSTANCE).addScalar("email", StringType.INSTANCE).addScalar("passe", StringType.INSTANCE).addScalar("loginType", IntegerType.INSTANCE)
        .setResultTransformer(Transformers.aliasToBean(User2DTO.class));

    List<User2DTO> userList = q.list();
}

A
Akash

我们已使用以下方式解决了该问题:

   //Add actual table name here in Query
    final String sqlQuery = "Select a.* from ACTORS a"
    // add your entity manager here 
    Query query = entityManager.createNativeQuery(sqlQuery,Actors.class);
    //List contains the mapped entity data.
    List<Actors> list = (List<Actors>) query.getResultList();

D
Darshan Patel

由于其他人已经提到了所有可能的解决方案,我正在分享我的解决方法。

在我使用 Postgres 9.4 的情况下,在使用 Jackson 时,

//Convert it to named native query.
List<String> list = em.createNativeQuery("select cast(array_to_json(array_agg(row_to_json(a))) as text) from myschema.actors a")
                   .getResultList();

List<ActorProxy> map = new ObjectMapper().readValue(list.get(0), new TypeReference<List<ActorProxy>>() {});

我相信你可以为其他数据库找到相同的。

仅供参考,JPA 2.0 native query results as map


R
Rubens

使用 ResultSet 的旧样式

@Transactional(readOnly=true)
public void accessUser() {
    EntityManager em = this.getEntityManager();
    org.hibernate.Session session = em.unwrap(org.hibernate.Session.class);
    session.doWork(new Work() {
        @Override
        public void execute(Connection con) throws SQLException {
            try (PreparedStatement stmt = con.prepareStatement(
                    "SELECT u.username, u.name, u.email, 'blabla' as passe, login_type as loginType FROM users u")) {
                ResultSet rs = stmt.executeQuery();
                ResultSetMetaData rsmd = rs.getMetaData();
                for (int i = 1; i <= rsmd.getColumnCount(); i++) {
                    System.out.print(rsmd.getColumnName(i) + " (" + rsmd.getColumnTypeName(i) + ") / ");
                }
                System.out.println("");
                while (rs.next()) {
                    System.out.println("Found username " + rs.getString("USERNAME") + " name " + rs.getString("NAME") + " email " + rs.getString("EMAIL") + " passe " + rs.getString("PASSE") + " email " + rs.getInt("LOGIN_TYPE"));
                }
            }
        }
    });
}

A
Andreas L.

不确定这是否适合这里,但我有类似的问题,并为我找到了以下简单的解决方案/示例:

private EntityManager entityManager;
...
    final String sql = " SELECT * FROM STORE "; // select from the table STORE
    final Query sqlQuery = entityManager.createNativeQuery(sql, Store.class);

    @SuppressWarnings("unchecked")
    List<Store> results = (List<Store>) sqlQuery.getResultList();

在我的情况下,我不得不在其他地方使用 Strings 中定义的 SQL 部分,所以我不能只使用 NamedNativeQuery。


一旦我们返回实体。没有什么花哨。问题是当您尝试将结果映射到非托管 POJO 时。
J
Jonathan L

请参阅下面的示例,了解使用 POJO 作为伪实体从本机查询中检索结果,而不使用复杂的 SqlResultSetMapping。 POJO 中只需要两个注释,一个裸露的@Enity 和一个虚拟的@Id。 @Id 可以在您选择的任何字段上使用,@Id 字段可以有重复的键但不能有空值。

由于@Enity 不映射到任何物理表,所以这个POJO 被称为伪实体。

环境:eclipselink 2.5.0-RC1、jpa-2.1.0、mysql-connector-java-5.1.14

您可以下载完整的 Maven 项目 here

本机查询基于 mysql 示例employees db http://dev.mysql.com/doc/employee/en/employees-installation.html

持久性.xml

<?xml version="1.0" encoding="UTF-8"?><persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.1" 
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="jpa-mysql" transaction-type="RESOURCE_LOCAL">
    <class>org.moonwave.jpa.model.pojo.Employee</class>
    <properties>
        <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/employees" />
        <property name="javax.persistence.jdbc.user" value="user" />
        <property name="javax.persistence.jdbc.password" value="***" />
        <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
    </properties>
</persistence-unit>

雇员.java

package org.moonwave.jpa.model.pojo;

@Entity
public class Employee {

@Id
protected Long empNo;

protected String firstName;
protected String lastName;
protected String title;

public Long getEmpNo() {
    return empNo;
}
public void setEmpNo(Long empNo) {
    this.empNo = empNo;
}
public String getFirstName() {
    return firstName;
}
public void setFirstName(String firstName) {
    this.firstName = firstName;
}
public String getLastName() {
    return lastName;
}
public void setLastName(String lastName) {
    this.lastName = lastName;
}   
public String getTitle() {
    return title;
}
public void setTitle(String title) {
    this.title = title;
}
public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("empNo: ").append(empNo);
    sb.append(", firstName: ").append(firstName);
    sb.append(", lastName: ").append(lastName);
    sb.append(", title: ").append(title);
    return sb.toString();
}
}

EmployeeNativeQuery.java

public class EmployeeNativeQuery {
private EntityManager em;
private EntityManagerFactory emf;

public void setUp() throws Exception {
    emf=Persistence.createEntityManagerFactory("jpa-mysql");
    em=emf.createEntityManager();
}
public void tearDown()throws Exception {
    em.close();
    emf.close();
}

@SuppressWarnings("unchecked")
public void query() {
    Query query = em.createNativeQuery("select e.emp_no as empNo, e.first_name as firstName, e.last_name as lastName," + 
            "t.title from employees e join titles t on e.emp_no = t.emp_no", Employee.class);
    query.setMaxResults(30);
    List<Employee> list = (List<Employee>) query.getResultList();
    int i = 0;
    for (Object emp : list) {
        System.out.println(++i + ": " + emp.toString());
    }
}

public static void main( String[] args ) {
    EmployeeNativeQuery test = new EmployeeNativeQuery();
    try {
        test.setUp();
        test.query();
        test.tearDown();
    } catch (Exception e) {
        System.out.println(e);
    }
}
}

既然您的 list 据称是 Employee 的列表,为什么您的 for-each 循环会遍历类型 Object?如果您将 for-each 循环编写为 for(Employee emp : list),那么您会发现您的答案是错误的,并且您的列表内容不是员工,并且您取消的警告旨在提醒您注意这个潜在的错误。
@SuppressWarnings("unchecked") 用于抑制 List<Employee> list = (List<Employee>) query.getResultList(); 的警告将 for (Object emp : list) 更改为 for (Employee emp : list) 更好,但如果保留为 Object emp 则不会出错,因为 list 是 List<Employee> 的实例。我更改了 git 项目中的代码,但不是在这里让您的评论与原始帖子相关
问题是您的查询不返回雇员列表,而是返回一个对象数组。您的抑制警告隐藏了这一点。在您尝试将其中任何一个转换为员工的那一刻,您将收到一个错误,即强制转换异常。
查看 Query query = em.createNativeQuery("select * ...", Employee.class); 和 persistence.xml,本机查询确实返回了 Employee 列表。我刚刚签出并运行没有问题的项目。如果您在本地设置 mysql 示例员工数据库,您应该也可以运行该项目
哦,我明白你现在的意思了。但在那种情况下,您的答案不能满足问题,因为这是关于使用常规 POJO 作为目标对象,而您的答案是使用 Employee,我认为它是一个实体。不是吗?
M
Marco Ferrari

如果您使用的是 Spring,则可以使用 org.springframework.jdbc.core.RowMapper

这是一个例子:

public List query(String objectType, String namedQuery)
{
  String rowMapper = objectType + "RowMapper";
  // then by reflection you can instantiate and use. The RowMapper classes need to follow the naming specific convention to follow such implementation.
} 

R
Rubens

使用休眠:

@Transactional(readOnly=true)
public void accessUser() {
    EntityManager em = repo.getEntityManager();
    org.hibernate.Session session = em.unwrap(org.hibernate.Session.class);
    org.hibernate.SQLQuery q = (org.hibernate.SQLQuery) session.createSQLQuery("SELECT u.username, u.name, u.email, 'blabla' as passe, login_type as loginType FROM users u")
        .addScalar("username", StringType.INSTANCE).addScalar("name", StringType.INSTANCE)
        .addScalar("email", StringType.INSTANCE).addScalar("passe", StringType.INSTANCE)
        .addScalar("loginType", IntegerType.INSTANCE)
        .setResultTransformer(Transformers.aliasToBean(User2DTO.class));

    List<User2DTO> userList = q.list();
}

A
Ankit kaushik

我尝试了上面答案中提到的很多事情。 SQLmapper 对放置它的位置非常困惑。只有非托管 POJO 是个问题。我尝试了各种方法,其中一种简单的方法就是照常工作。我正在使用hibernate-jpa-2.1。

List<TestInfo> testInfoList = factory.createNativeQuery(QueryConstants.RUNNING_TEST_INFO_QUERY)
                    .getResultList();

唯一需要注意的是 POJO 具有与查询相同的成员变量名称(全部小写)。显然,我什至不需要像我们在 JPQL 中使用 TypedQueries 那样告诉目标类和查询。

测试信息类

@Setter
@Getter
@NoArgsConstructor
@ToString
public class TestInfo {

    private String emailid;
    private Long testcount;

    public TestInfo(String emailId, Long testCount) {
        super();
        this.emailid = emailId;
        this.testcount = testCount;
    }

}

D
Dharman

在这种情况下,使用像实体(又名不可变实体)这样的“数据库视图”非常容易。

正常实体

@Entity
@Table(name = "people")
data class Person(
  @Id
  val id: Long = -1,
  val firstName: String = "",
  val lastName: String? = null
)

查看类似实体

@Entity
@Immutable
@Subselect("""
select
    p.id,
    concat(p.first_name, ' ', p.last_name) as full_name
from people p
""")
data class PersonMin(
  @Id
  val id: Long,
  val fullName: String,
)

在任何存储库中,我们都可以创建查询函数/方法,就像:

@Query(value = "select p from PersonMin p")
fun findPeopleMinimum(pageable: Pageable): Page<PersonMin>

m
marengz

如果查询不是太复杂,你可以做这样的事情。在我的情况下,我需要使用 H2 FT_Search 结果查询来进行另一个查询。

var ftSearchQuery = "SELECT * FROM FT_SEARCH(\'something\', 0, 0)";
List<Object[]> results = query.getResultList();
List<Model> models = new ArrayList<>();
for (Object[] result : results) {
    var newQuery = "SELECT * FROM " + (String) result[0];
    models.addAll(entityManager.createNativeQuery(newQuery, Model.class).getResultList());
  }

可能有更清洁的方法可以做到这一点。


P
Parth Solanki

将 SQL 查询转换为 POJO 类集合的简单方法,

Query query = getCurrentSession().createSQLQuery(sqlQuery).addEntity(Actors.class);
List<Actors> list = (List<Actors>) query.list();
return list;

Z
Zaw Than oo

使用 DTO Design Pattern。它在 EJB 2.0 中使用。实体是容器管理的。 DTO Design Pattern 用于解决此问题。但是,现在可能会使用它,当应用程序分别开发 Server SideClient Side 时。当 Server side 不想将带有注释的 Entity 传递/返回给 Client Side 时使用DTO

DTO 示例:

个人实体.java

@Entity
public class PersonEntity {
    @Id
    private String id;
    private String address;

    public PersonEntity(){

    }
    public PersonEntity(String id, String address) {
        this.id = id;
        this.address = address;
    }
    //getter and setter

}

PersonDTO.java

public class PersonDTO {
    private String id;
    private String address;

    public PersonDTO() {
    }
    public PersonDTO(String id, String address) {
        this.id = id;
        this.address = address;
    }

    //getter and setter 
}

DTOBuilder.java

public class DTOBuilder() {
    public static PersonDTO buildPersonDTO(PersonEntity person) {
        return new PersonDTO(person.getId(). person.getAddress());
    }
}

EntityBuilder.java <-- 它是需要的

public class EntityBuilder() {
    public static PersonEntity buildPersonEntity(PersonDTO person) {
        return new PersonEntity(person.getId(). person.getAddress());
    }
}

感谢您的回答。这里我不需要 DTO 模式。我的要求是不要向客户隐藏注释细节。所以我不需要在我的应用程序中再创建一个 POJO。我的要求是将结果集转换为 qa pojo,它不是 JAVA 实体,而是具有与结果集列相同的字段的简单 POJO 类。

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅