Utilisation requête arbitraire projection dans les données ressort projet de repos

Lubo:

Comment est-il possible d'utiliser arbitraire de requêtes SQL (je veux dire requête SQL native) dans certains dépôt? Mon problème réel est le suivant:

@Data //lombok thing
@Entity
public class A extends AuditModel {
  private long id;
  private String name;

  @OneToMany(mappedBy="a") //Comments.a is owning side of association, i.e. comments table does have column called a_id as foreign key
  @ToString.Exclude
  private Set<Comments> comments = new HashSet();

  @OneToMany(mappedBy="a") //SimpleFile.a is owning side of association
  private Set<SimpleFile> comments = new HashSet();
}

Que moi mon dépôt, ce qui expose belle interface crud en utilisant la représentation de HAL +. Je suis en train de l'enrichir avec une projection / vue notamment en raison de l'interface utilisateur Web pour charger une donnée de page dans la demande unique. Je suis conscient des excerps et des projections, mais ils ne semble pas être assez puissant.

@Repository
@RepositoryRestResource
@Transactional(readOnly = true)
public interface ARepository extends PagingAndSortingRepository<A, Long> {
  Page<A> findByNameContaining(String namePart, Pageable pageable);
  @Query(
    value = "SELECT a.name,\n" +
      "(SELECT CAST(count(ac.id) AS int) FROM COMMENTS ac WHERE ac.a_id = a.id),\n" +
      "(SELECT listagg(asf.id) FROM SIMPLE_FILES asf WHERE asf.a_id = a.id)\n" +
      "FROM AS a\n" +
      "WHERE a.id = :id",
    nativeQuery = true
  )
  Optional<ACustomPage42DTO> getByIdProjectedForScreen42(Long id);
}

J'ai aussi essayé d'utiliser JPQL, mais j'ai eu problème avec fetch rejoindre (comme je ne suis pas familier avec JPQL). Ma dernière requête d'évaluation était quelque chose comme ceci:

@Query("SELECT new sk.qpp.qqq.documents.projections.ACustomPage42DTO(" +
  "a " +
  "(SELECT CAST(count(ac) AS int) FROM COMMENTS ac WHERE ac.a = a)" +
  ")\n" +
  "FROM A a\n" +
  "LEFT JOIN FETCH a.simpleFiles\n" +
  "WHERE a.id = :id"
)

Je voudrais obtenir des conseils généraux sur quelle approche est la meilleure pour mettre en œuvre personnalisée et requête complexe à retourner dans DTO (idéalement avec des liens spécifiques à des actions en cas de besoin).

PS: La mise en œuvre interface et retour simples (primitifs) œuvres de données. En utilisant également JPQL pour créer des œuvres personnalisées d'instance de DAO (avec des types simples et avec instance unique de type Apar exemple). Méthode selon la méthode de requête donnée ne figure dans les méthodes de recherche de point d'extrémité entité donnée. Je voudrais avoir quelque chose de plus raisonnable, donc je voudrais avoir la projection tel que défini dans les données du printemps repos projet.

J'ai mon objet DTO entièrement sous mon contrôle. Je préfère utiliser @Valueou @Dataannotation du projet lombok, mais ce n'est pas un besoin. J'ai essayé ces versions de définition DTO ( à l' aide des œuvres d'interface pour les données simples et fonctionne de la même classe pour les données simples).

interface ACustomPage42DTO {
    String getName();
    long getCommentsCount();
    Object getAsdf();
}

Ou en utilisant la classe équivalente avec quelques bonus, comme méthode toString () personnalisée possible, ou d'un getter personnalisé pour les données calculées:

@Value //lombok thing, imutable "POJO"
public class ACustomPage42DTO {
    String name;
    long commentsCount;
    Set<SimpleFile> simpleFiles;
    public ACustomPage42DTO(A a, long count) {
        // constructor used by JPQL, if it works
        name = a.getName();
        this.commentsCount = count;
        this.simpleFiles = a.getSimpleFiles(); // should be already fetched, due to fetch join in JPQL
    }
}

Les deux approches de travail peuvent être appelées à l' aide url « recherche », au lieu de projection. Je vois ma méthode getByIdProjectedForScreen42sur l' URL http: // localhost: 9091 / api / a / search liste. Je voudrais l' utiliser comme (je pense que c'est la « bonne ») http: // localhost: 8080 / api / projection = ACustomPage42DTOProjection .

Aivaras:

La question est assez large et touche deux aspects:

  • méthode personnalisée référentiel JPA à l'aide @Query
  • la sélection des résultats dans votre @Query
  • le mappage des @Queryrésultats d'une interface
  • exposer nouvelle méthode par dépôt @RepositoryRestResource

TLDR: a écrit un exemple de ce qui est parlé avec quelques tests de base https://github.com/ivarprudnikov/test-spring-jpa-repository-query-exposed-through-http

méthode personnalisée référentiel JPA à l'aide @Query

Comme vous l' avez mentionné , il est assez simple, juste annoter une méthode avec @Queryet assurez - vous que votre correspond de type de retour à ce qui est de retour de la requête, par exemple:

public interface FooRepository extends JpaRepository<FooEntity, Long> {
    @Query(nativeQuery = true, value = "select f from foo f where f.name = :myParam")
    Optional<FooEntity> getInSomeAnotherWay(String myParam);
}

la sélection des résultats dans votre @Query

Vous avez donné un exemple déjà, mais je vais simplifier pour le rendre plus facile et plus court.

Compte tenu des entités FooEntity.javaet BarEntity.java:

@Entity
@Table(name = "foo")
public class FooEntity {

    @Id
    @Column(name = "id", unique = true, nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name", nullable = false)
    private String name;

    @OneToMany(mappedBy = "foo")
    private Set<BarEntity> bars = new HashSet<>();

    // getter setters excluded for brevity
}

@Entity
@Table(name = "bar")
public class BarEntity {

    @Id
    @Column(name = "id", unique = true, nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "name", nullable = false)
    private String name;

    @ManyToOne(targetEntity = FooEntity.class)
    @JoinColumn(name = "foo_id", nullable = false, foreignKey = @ForeignKey(name = "fk_bar_foo"))
    private FooEntity foo;

    // getter setters excluded for brevity
}

Nous voulons maintenant de retour de résultat PERSO qui contient FooEntity.nameet le nombre de FooEntity.bars:

SELECT f.name as name, count(b.id) as barCount FROM foo f, bar b WHERE f.id = :id AND b.foo_id = :id


+-----------------+----------+
| name            | barCount |
+-----------------+----------+
| Jonny tables    | 1        |
+-----------------+----------+

le mappage des @Queryrésultats d'une interface

Pour la carte ci-dessus nous avons besoin ensemble de résultats d'une interface où getters reflètent bien ce qui est sélectionné:

public interface ProjectedFooResult {
    String getName();
    Long getBarCount();
}

Maintenant, nous pouvons réécrire notre méthode référentiel pour:

@Query(nativeQuery = true, 
    value = "SELECT f.name as name, count(b.id) as barCount FROM foo f, bar b WHERE f.id = :id AND b.foo_id = :id")
Optional<ProjectedFooResult> getByIdToProjected(Long id);

exposer nouvelle méthode par dépôt @RepositoryRestResource

Je ne suis pas très familier avec cela , mais après avoir ajouté la org.springframework.data:spring-data-rest-hal-browserdépendance j'ai eu cette belle interface que les méthodes disponibles exposées après dépôt a été annotés avec @RepositoryRestResource. Pour un référentiel donné , qui contient plus de détails mentionnés:

@RepositoryRestResource(path = "foo")
public interface FooRepository extends JpaRepository<FooEntity, Long> {
    @Query(nativeQuery = true, value = "SELECT f.name as name, count(b.id) as barCount FROM foo f, bar b WHERE f.id = :id AND b.foo_id = :id")
    Optional<ProjectedFooResult> getByIdToProjected(Long id);
}

la méthode sera exposée à travers http://localhost:8080/foo/search/getByIdToProjected?id=1lors de l' exécution au niveau local.

Comme mentionné plus haut la mise en œuvre de référence est sur Github https://github.com/ivarprudnikov/test-spring-jpa-repository-query-exposed-through-http

documentation supplémentaire utile pour « personnalisés pour Implémentations Référentiels de données Spring »

Je suppose que tu aimes

Origine http://43.154.161.224:23101/article/api/json?id=280294&siteId=1
conseillé
Classement