web-dev-qa-db-fra.com

Dépôts de données JPA avec SqlResultSetMapping et requêtes natives

J'étais coincé avec la situation suivante:

Mes entités sont liées les unes aux autres, mais de telle sorte que je ne puisse pas utiliser JPQL. J'ai été obligé d'utiliser le SQL natif. Maintenant, je veux mapper ces résultats sur un ValueObject. Pour être clair, je ne veux pas obtenir une liste de tableau d'objets (List<Object[]>). J'ai 6 entités dont je n'ai besoin que de quelques colonnes. Quelqu'un peut-il me donner un exemple sur la façon de mettre en œuvre un tel mappage à partir d'une requête native?

Tutorial que j'ai traversé.

Mon code:

@SqlResultSetMapping(
    name = "findAllDataMapping",
    classes = @ConstructorResult(
            targetClass = MyVO.class,
            columns = {
                    @ColumnResult(name = "userFirstName"),
                    @ColumnResult(name = "userLastName"),
                    @ColumnResult(name = "id"),
                    @ColumnResult(name = "packageName")
            }
    )
)

@NamedNativeQuery(name = "findAllDataMapping",
    query = "SELECT " +
            "    u.first_name as userFirstName, " +
            "    u.last_name as userLastName, " +
            "    i.id as id, " +
            "    s.title as packageName, " +
            "FROM " +
            "    invoice as i " +
            "JOIN user as u on i.user_id=u.id " +
            "LEFT JOIN subscription_package as s on i.subscription_package_id=s.id " +
            "where  u.param1=:param1 and i.param2=:param2" +
)

public class MyVO {
    private String userFirstName;
    private String userLastName;
    private Long id;
    private String packageName;

    public MyVO (String userFName, String userLName,
            Long id, String packageName) {
        this.userFirstName = userFName;
        this.userLastName = userLName;
        this.id = id;
        this.packageName = packageName;
    }

    // getters & setters
}

Dans mon module jpa-repository:

public interface MyRepository extends JpaRepository<MyEntity, Long> {
    List<MyVO> findAllOfMyVO(@Param("param1") String param1, @Param("param2") String param2);
}

Le fait est que je ne sais pas où mettre ces annotations pour pouvoir utiliser ce type de mappage. Dans une requête native, je ne peux pas utiliser new rs.rado.leo.mypackage.MyVO(...). J'ai eu l'erreur suivante: 

Causé par: 

org.springframework.data.mapping.PropertyReferenceException: No property findAllOfMyVO found for type MyEntity!

Je suppose que ma question est claire. Sinon, faites le moi savoir afin que je puisse modifier ma question.

Merci d'avance!

10
LeoRado

Ajouter le résultat manquant

@NamedNativeQuery(name = "findAllDataMapping", resultClass = Entity.class, query="sql")

Ou

@NamedNativeQuery(name = "findAllDataMapping", resultClass = MyVO.class, resultSetMapping ="findAllDataMapping" query = "sql")

et enfin appeler la requête dans votre référentiel 

@Query(nativeQuery = true, name = "findAllDataMapping")
List<MyVO> findAllOfMyVO(@Param("param1") String param1, @Param("param2") String param2);
7
Michelan Arendse

Vous devez marquer votre requête en tant que requête:) Et vous devez utiliser MyVO au lieu de MyEntity , car il s'agit de l'entité à laquelle vos résultats sont associés

@Repository
public interface MyRepository extends JpaRepository<MyVO, Long> {

    @Query(nativeQuery = true)
    List<MyVO> findAllOfMyVO(@Param("param1") String param1, @Param("param2") String param2);
}
0
Urosh T.

Vous êtes presque là, mais pour les parties ci-dessous

  1. L'ensemble @SqlResultSetMapping et @NamedNativeQuery doit être présent dans l'entité et non dans la valeur Object. Dans votre cas, il devrait être dans la classe MyEntity et ** pas ** dans la classe MyVO. Cela devrait résoudre votre exception.
  2. Cela ne fera toujours pas. Après avoir fait ce qui précède, modifiez ce qui suit 

    @NamedNativeQuery (name = "findAllDataMapping", À
    @NamedNativeQuery (name = " MyEntity . FindAllDataMapping",

  3. Enfin, dans certains cas, vous devez être explicite dans votre définition de @ColumnResult (name = "userFirstName"). S'il s'agit d'un champ complexe comme ZonedDateTime ou Boolean, vous devrez peut-être explicitement définir l'état @ColumnResult (name = "date_created", tapez = ZonedDateTime.class).

J'espère que cela pourra aider.

0
HopeKing