Отображение результатов NativeQuery в POJO
Я пытаюсь сопоставить результаты собственного запроса с POJO, используя @SqlResultSetMapping с @ConstructorResult. Вот мой код:
@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;
...
А затем в моем Дао:
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]
5 ответов:
@SqlResultSetMapping
аннотацию не следует ставить на POJO . Поместите его в (любой)@Entity
класс. "Unknown SqlResultSetMapping [foo]" говорит вам, что поставщик JPA не видит никакого отображения под именем "foo". Пожалуйста, смотрите другой мой ответ для правильного примера
Краткий рабочий пример:
Класс DTO POJO
@lombok.Getter @lombok.AllArgsConstructor public class StatementDto { private String authorName; private Date createTime; }
Боб репозитория:
@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;} // <- walkaround }
Я могу сделать это следующим образом:
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 @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
контент соответствующий пакет, если вы используете конфигурацию spring на основе 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/
QLRM может быть альтернативой: http://simasch.github.io/qlrm/
Он не связан с конкретной реализацией JPA и также работает с JDBC.