web-dev-qa-db-fra.com

Mappage des résultats NativeQuery dans un POJO

J'essaie de mapper les résultats d'une requête native sur un POJO à l'aide de @SqlResultSetMapping avec @ConstructorResult. Voici mon code:

@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;

...

Et puis dans mon DAO:

Query query = em.createNativeQueryBar(QUERY, "foo");
... set some parameters ...
List<Bar> list = (List<Bar>) query.getResultList();

J'ai lu que cette fonctionnalité n'est prise en charge que dans JPA 2.1, mais c'est ce que j'utilise. Voici ma dépendance:

        <dependency>
            <groupId>org.hibernate.javax.persistence</groupId>
            <artifactId>hibernate-jpa-2.1-api</artifactId>
            <version>1.0.0.Final</version>
        </dependency>

J'ai trouvé quelques ressources, dont celle-ci: @ConstructorResult mapping in jpa 2.1 . Mais je n'ai toujours pas de chance.

Qu'est-ce que je rate? Pourquoi le SqlResultSetMapping ne peut-il pas être trouvé?

javax.persistence.PersistenceException: org.hibernate.MappingException: Unknown SqlResultSetMapping [foo]
28
mhlandry

@SqlResultSetMapping annotation ne doit pas être placé sur un POJO. Mettez-le à (n'importe quel) classe @Entity. "Unknown SqlResultSetMapping [foo]" vous indique que le fournisseur JPA ne voit aucun mappage sous le nom "foo". S'il vous plaît voir une autre de mes réponses pour le bon exemple

28
zbig

Exemple de travail court:

  • DTO POJO class

    @lombok.Getter
    @lombok.AllArgsConstructor
    public class StatementDto {
        private String authorName;
        private Date createTime;
    }
    
  • Bean de référentiel:

    @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
    
    }
    
9
wildloop

Je suis capable de le faire de cette façon:

Session session = em().unwrap(Session.class);
SQLQuery q = session.createSQLQuery("YOUR SQL HERE");
q.setResultTransformer( Transformers.aliasToBean( MyNotMappedPojoClassHere.class) );
List<MyNotMappedPojoClassHere> postList = q.list();
5
Emerson Moretto

J'ai une réponse légèrement variée qui vient juste de la réponse de wildloop.
Voici ma réponse:

Classe Constants: Constants.Java

public class Constants {
    public final String TESTQUERYRESULT_MAPPING_NAME = "TestQueryResultMapping";
}

Classe de mappage des résultats: 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;

}

Alors ... quelque part dans mon code d'implémentation de référentiel: 

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;
    }

}


... alors violah! J'ai eu quelques résultats: D!

À votre santé,
Artanis Zeratul

0
Artanis Zeratul

QLRM pourrait être une alternative: http://simasch.github.io/qlrm/

Il n'est pas lié à une implémentation JPA spécifique et fonctionne également avec JDBC.

0
Simon Martinelli