@SqlResultSetMappingと@ConstructorResultを使用して、ネイティブクエリの結果を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>
これを含むいくつかのリソースを見つけました: jpa 2.1の@ConstructorResultマッピング 。しかし、私はまだ運がありません。
私は何が欠けていますか? SqlResultSetMappingが見つからないのはなぜですか?
javax.persistence.PersistenceException: org.hibernate.MappingException: Unknown SqlResultSetMapping [foo]
@SqlResultSetMapping
注釈は、POJOには配置しないでください。 (any)@Entity
クラス。 「不明なSqlResultSetMapping [foo]」は、JPAプロバイダーには「foo」という名前のマッピングが表示されないことを示しています。正しい例については、私の別の答えをご覧ください
短い作業例:
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
}
私はこのようにすることができます:
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
コンテンツが対応するパッケージであることを確認する必要があります。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でも機能します。
@Entity
をDTO POJOに追加する際の問題は、dbに不要なテーブルを作成することです。 @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がマッピングを自動配線します。
私はワイルドループの答えから派生したわずかに多様な答えを持っています。
私の答えは次のとおりです。
定数クラス:Constants.Java
public class Constants {
public final String TESTQUERYRESULT_MAPPING_NAME = "TestQueryResultMapping";
}
結果マッピングクラス:TestQueryResult.Java
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;
}
その後...私のリポジトリ実装コードのどこかに:
public class TestQueryRepository {
//... some code here to get the entity manager here
public TestQueryResult getTopMost(Integer rowName) {
//... some code here
String queryString = "... some query string here" + rowName;
TestQueryResult testQueryResult = null;
//this.entityManager.createNativeQuery(queryString ,"TestQueryResultMapping").getResultList();
List<TestQueryResult> results = this.entityManager.createNativeQuery(queryString ,Constants.TESTQUERYRESULT_MAPPING_NAME).getResultList();
if (results != null && !results.isEmpty()) {
testQueryResult = results.get(0);
}
return testQueryResult;
}
}
...それからビオラ!私はいくつかの結果を得ました:D!
乾杯、
アルタニス・ゼラトゥル