我在我的项目中使用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类?


当前回答

如果您使用Spring-jpa,这是对答案和这个问题的补充。如有任何瑕疵,请改正。根据我的实际需求,我主要使用了三种方法来实现“map result Object[] to a pojo”:

JPA内置方法就足够了。 JPA内置的方法是不够的,但一个自定义的sql与它的实体是足够的。 前2失败,我必须使用一个nativeQuery。 下面是一些例子。 pojo期待着: 公共类 private String; private Integer successRate; // getter和setter public Antistealingdto(String secretKey, Integer successRate) { 这一点。secretKey = secretKey; 这一点。successRate =成功率; } }

方法1:将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: 在Edwin Dalorzo的回答中,以实体中的@SqlResultSetMapping和@NamedNativeQuery为例。

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

其他回答

是的,使用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

下面你可以添加resultset映射声明:

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

就是这样。

使用DTO设计模式。它在EJB 2.0中使用。实体由容器管理。采用DTO设计模式来解决这一问题。 但是,当应用程序分别开发服务器端和客户端时,现在可能会使用它。DTO用于服务器端不想将带有注释的实体传递/返回给客户端。

DTO示例:

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

java <——可能需要

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

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

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

在我的情况下,我必须使用在其他地方的字符串中定义的SQL部分,所以我不能只使用NamedNativeQuery。

如果希望将自定义查询结果直接映射到实体,而不需要编写任何映射代码,可以尝试这种方式。根据我的经验,这是最方便的方法,但缺点是失去了hibernate ddl-auto的好处:

Disable hibernate validation by removing the hibernate.ddl-auto. If not doing this, hibernate can complain about missing table in database. Create a pojo with @Entity for the custom result set without table mapping, something like: @Getter @Setter @Entity public class MyCustomeResult implements Serializable { @Id private Long id; @Column(name = "name") private String name; } In repository, use the entity to map directly from query.getResultList() public List<MyCustomeResult> findByExampleCustomQuery(Long test) { String sql = "select id, name from examples where id =:test"; Query query = entityManager.createNativeQuery(sql, MyCustomeResult.class); return query.setParameter("test", test).getResultList(); }

使用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"));
                }
            }
        }
    });
}