web-dev-qa-db-fra.com

Comment extraire uniquement les attributs sélectionnés d'une entité à l'aide de Spring JPA?

J'utilise Spring Boot (1.3.3.RELEASE) et Hibernate JPA dans mon projet. Mon entité ressemble à ceci:

@Data
@NoArgsConstructor
@Entity
@Table(name = "rule")
public class RuleVO {

    @Id
    @GeneratedValue
    private Long id;

    @Column(name = "name", length = 128, nullable = false, unique = true)
    private String name;

    @Column(name = "tag", length = 256)
    private String tag;

    @OneToMany(mappedBy = "rule", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<RuleOutputArticleVO> outputArticles;

    @OneToMany(mappedBy = "rule", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<RuleInputArticleVO> inputArticles;
}

Mon référentiel ressemble à ceci:

@Repository
public interface RuleRepository extends JpaRepository<RuleVO, Long> {
}

Dans certains cas, je dois extraire uniquement les attributs id et name de l'entité RuleVO. Comment puis-je atteindre cet objectif? J'ai trouvé un avis qui devrait être faisable à l'aide de Criteria API et Projections, mais comment? Merci d'avance. Vojtech

9
Vojtech

METTRE À JOUR:

Comme on m'a fait remarquer, je suis paresseux et cela peut très bien être fait, donc je mets à jour ma réponse après avoir regardé sur le Web pour en trouver une bonne.

Voici un exemple montrant comment obtenir uniquement l'id et uniquement les noms:

@Repository
public interface RuleRepository extends JpaRepository<RuleVO, Long> {

    @Query("SELECT r.id FROM RuleVo r where r.name = :name") 
    List<Long> findIdByName(@Param("name") String name);

    @Query("SELECT r.name FROM RuleVo r where r.id = :id") 
    String findNameById(@Param("id") Long id);
}

Espérons que cette mise à jour s'avère utile


Ancienne réponse:

Récupérer uniquement les attributs spécifiques nom/id n'est pas possible car ce n'est pas ainsi que Spring a été conçu ou une base de données SQL, car vous sélectionnez toujours une ligne qui est une entité.

Ce que vous POUVEZ faire, c'est interroger les variables de l'entité, par exemple:

@Repository
public interface RuleRepository extends JpaRepository<RuleVO, Long> {

    public RuleVo findOneByName(String name);
    public RuleVo findOneByNameOrId(String name, Long id);
    public List<RuleVo> findAllByName(String name);
    // etc, depending on what you want
}

Vous pouvez les modifier comme bon vous semble. vos besoins. Vous pouvez appeler ces méthodes directement via le référentiel auto-câblé

Voir http://docs.spring.io/spring-data/jpa/docs/current/reference/html/ Section 5.3 pour plus d'options et d'exemples.

10
Roel Strolenberg

Oui, vous pouvez y arriver avec des projections. Vous avez plusieurs façons de les appliquer:

Si vous pouviez effectuer une mise à niveau vers Spring Data Hopper, il fournit un support facile à utiliser pour les projections. Voir comment les utiliser dans documentation de référence .

Sinon, créez d'abord un DTO avec les attributs que vous voulez charger, quelque chose comme:

package org.example;

public class RuleProjection {

    private final Long id;

    private final String name;

    public RuleProjection(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

Bien sûr, vous pouvez également utiliser les annotations de Lombok.

Ensuite, vous pouvez utiliser dans les requêtes JPQL comme ceci:

select new org.example.RuleProjection(rule.id, rule.name) from RuleVO rule order by rule.name

Si vous souhaitez éviter d'utiliser des noms de classe DTO dans vos requêtes, vous pouvez également implémenter votre propre méthode de requête à l'aide de QueryDSL. Avec Spring Data JPA, vous devez:

  • Créez une nouvelle interface avec la nouvelle méthode. Ex:

    public interface RuleRepositoryCustom {
       public List<RuleProjection> findAllWithProjection();
    }
    
  • Modifiez votre référentiel pour étendre la nouvelle interface. Ex:

    public interface RuleRepository extends JpaRepository<RuleVO, Long>, RuleRepositoryCustom {
    ...
    
  • Créez une implémentation du référentiel personnalisé à l'aide du support Spring Data JPA QueryDSL. Vous devez préalablement générer les classes Q de QueryDSL, à l’aide de son plug-in Maven. Ex:

    public class RuleRepositoryImpl {
    
        public List<RuleProjection> findAllWithProjection() {
            QRuleVO rule = QRuleVO.ruleVO;
            JPQLQuery query = getQueryFrom(rule);     
            query.orderBy(rule.name.asc());
            return query.list(ConstructorExpression.create(RuleProjection.class, rule.id, rule.name));
        }
    }
    
3
Cèsar

Vous pouvez le faire en utilisant l'annotation @Query (HQL).

Veuillez vous référer à la documentation Spring ci-dessous:

http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query

(recherche de @Query dans le document de printemps)

2
shankarsh15

Vous pouvez également définir un constructeur personnalisé pour extraire des colonnes spécifiques à l'aide de JPQL.

Exemple:

Remplacez {javaPackagePath} par le chemin d'accès complet au package Java de la classe utiliser comme constructeur dans JPQL.

public class RuleVO {
   public RuleVO(Long id, String name) {
    this.id = id;
    this.name = name;
   }
}


@Repository
public interface RuleRepository extends JpaRepository<RuleVO, Long> {

    @Query("SELECT new {javaPackagePath}.RuleVO(r.id, r.name) FROM RuleVo r where r.name = :name") 
    List<RuleVO> findIdByName(@Param("name") String name);
}
1
Abhilekh Singh
interface IdOnly{
    String getId();
}

@Repository
public interface RuleRepository extends JpaRepository<RuleVO, Long> {
    public List<IdOnly> findAllByName(String name);
}

Je remarque que c'est un très vieux billet, mais si quelqu'un cherche toujours une réponse, essayez ceci. Cela a fonctionné pour moi.

0
Pranjal Gore