web-dev-qa-db-fra.com

Spring JPA sélectionnant des colonnes spécifiques

J'utilise Spring JPA pour effectuer toutes les opérations de base de données. Cependant, je ne sais pas comment sélectionner des colonnes spécifiques d'une table dans Spring JPA?

Par exemple:
SELECT projectId, projectName FROM projects

106
user1817436

Vous pouvez définir nativeQuery = true dans l'annotation @Query à partir d'une classe Repository comme suit:

public static final String FIND_PROJECTS = "SELECT projectId, projectName FROM projects";

@Query(value = FIND_PROJECTS, nativeQuery = true)
public List<Object[]> findProjects();

Notez que vous devrez cependant faire le mappage vous-même. Il est probablement plus facile d'utiliser simplement la recherche standard mappée comme ceci, à moins que vous n'ayez réellement besoin que de ces deux valeurs:

public List<Project> findAll()

Cela vaut probablement la peine de regarder les données Spring docs également.

55
Durandal

Je n'aime pas particulièrement la syntaxe (ça a l'air un peu hacky ...) mais c'est la solution la plus élégante que j'ai pu trouver (elle utilise une requête JPQL personnalisée dans la classe de référentiel JPA):

@Query("select new com.foo.bar.entity.Document(d.docId, d.filename) from Document d where d.filterCol = ?1")
List<Document> findDocumentsForListing(String filterValue);

Ensuite, bien sûr, vous devez simplement fournir un constructeur pour Document qui accepte docId & nom de fichier comme argument de constructeur.

115
jm0

Vous pouvez utiliser des projections à partir de Spring Data JPA (doc) . Dans votre cas, créez une interface:

interface ProjectIdAndName{
    String getId();
    String getName();
}

et ajouter la méthode suivante à votre référentiel

List<ProjectIdAndName> findAll();
113
mpr

Dans ma situation, je n'ai besoin que du résultat JSON, et cela fonctionne pour moi:

public interface SchoolRepository extends JpaRepository<School,Integer> {
    @Query("select s.id, s.name from School s")
    List<Object> getSchoolIdAndName();
}

dans le contrôleur:

@Autowired
private SchoolRepository schoolRepository;

@ResponseBody
@RequestMapping("getschoolidandname.do")
public List<Object> getSchool() {
    List<Object> schools = schoolRepository.getSchoolIdAndName();
    return schools;
}
13
Atal

Dans mon cas, j'ai créé une classe d'entité séparée sans les champs non obligatoires (uniquement avec les champs obligatoires).

Mappez l'entité sur la même table. Maintenant, lorsque toutes les colonnes sont requises, j'utilise l'ancienne entité, lorsque seules quelques colonnes sont requises, j'utilise l'entité Lite.

par exemple.

@Entity
@Table(name = "user")
Class User{
         @Column(name = "id", unique=true, nullable=false)
         int id;
         @Column(name = "name", nullable=false)
         String name;
         @Column(name = "address", nullable=false)
         Address address;
}

Vous pouvez créer quelque chose comme:

@Entity
@Table(name = "user")
Class UserLite{
         @Column(name = "id", unique=true, nullable=false)
         int id;
         @Column(name = "name", nullable=false)
         String name;
}

Cela fonctionne lorsque vous connaissez les colonnes à récupérer (et cela ne changera pas).

ne fonctionnera pas si vous devez décider dynamiquement des colonnes.

13
Sachin Sharma

J'imagine que le moyen le plus simple est peut-être d'utiliser QueryDSL , fourni avec Spring-Data.

En utilisant à votre question la réponse peut être

JPAQuery query = new JPAQuery(entityManager);
List<Tuple> result = query.from(projects).list(project.projectId, project.projectName);
for (Tuple row : result) {
 System.out.println("project ID " + row.get(project.projectId));
 System.out.println("project Name " + row.get(project.projectName)); 
}}

Le gestionnaire d'entités peut être câblé automatiquement et vous travaillerez toujours avec des objets et des classements sans utiliser le langage * QL.

Comme vous pouvez le voir sur le lien, le dernier choix semble presque, pour moi, plus élégant, c’est-à-dire utiliser DTO pour stocker le résultat. Appliquez à votre exemple qui sera:

JPAQuery query = new JPAQuery(entityManager);
QProject project = QProject.project;
List<ProjectDTO> dtos = query.from(project).list(new QProjectDTO(project.projectId, project.projectName));

Définir ProjectDTO comme:

class ProjectDTO {

 private long id;
 private String name;
 @QueryProjection
 public ProjectDTO(long projectId, String projectName){
   this.id = projectId;
   this.name = projectName;
 }
 public String getProjectId(){ ... }
 public String getProjectName(){....}
}
7
kszosze

À mon avis, c'est une excellente solution:

interface PersonRepository extends Repository<Person, UUID> {

    <T> Collection<T> findByLastname(String lastname, Class<T> type);
}

et l'utiliser comme si

void someMethod(PersonRepository people) {

  Collection<Person> aggregates =
    people.findByLastname("Matthews", Person.class);

  Collection<NamesOnly> aggregates =
    people.findByLastname("Matthews", NamesOnly.class);
}
4
Evgeni Atanasov
Using Spring Data JPA there is a provision to select specific columns from database


---- In DAOImpl ----
@Override
    @Transactional
    public List<Employee> getAllEmployee() throws Exception {
    LOGGER.info("Inside getAllEmployee");
    List<Employee> empList = empRepo.getNameAndCityOnly();
    return empList;
    }

---- In Repo ----
public interface EmployeeRepository extends CrudRepository<Employee,Integer> {
    @Query("select e.name, e.city from Employee e" )
    List<Employee> getNameAndCityOnly();
}

It worked 100% in my case.
Thanks.
2
SR Ranjan

Il est possible de spécifier null comme valeur de champ dans SQL natif.

@Query(value = "select p.id, p.uid, p.title, null as documentation, p.ptype " +
            " from projects p " +
            "where p.uid = (:uid)" +
            "  and p.ptype = 'P'", nativeQuery = true)
Project findInfoByUid(@Param("uid") String uid);
2
hahn

Avec les nouvelles versions de Spring, on peut procéder comme suit:

Si vous n'utilisez pas de requête native, procédez comme suit:

public interface ProjectMini {
    String getProjectId();
    String getProjectName();
}

public interface ProjectRepository extends JpaRepository<Project, String> { 
    @Query("SELECT p FROM Project p")
    List<ProjectMini> findAllProjectsMini();
}

En utilisant une requête native, la même chose peut être faite comme ci-dessous:

public interface ProjectRepository extends JpaRepository<Project, String> { 
    @Query(value = "SELECT projectId, projectName FROM project", nativeQuery = true)
    List<ProjectMini> findAllProjectsMini();
}

Pour plus de détails, consultez le docs

2
jombie

Vous pouvez appliquer le code ci-dessous dans votre classe d'interface de référentiel.

entityname signifie votre nom de table de base de données comme des projets. Et Liste signifie que le projet est la classe d'entité dans vos projets.

@Query(value="select p from #{#entityName} p where p.id=:projectId and p.projectName=:projectName")

List<Project> findAll(@Param("projectId") int projectId, @Param("projectName") String projectName);
2
ajaz

Vous pouvez utiliser JPQL:

TypedQuery <Object[]> query = em.createQuery(
  "SELECT p.projectId, p.projectName FROM projects AS p", Object[].class);

List<Object[]> results = query.getResultList();

ou vous pouvez utiliser la requête native SQL.

Query query = em.createNativeQuery("sql statement");
List<Object[]> results = query.getResultList();
1
Henrik

La plupart des réponses suggèrent d'utiliser une variante de la requête SQL native. Cependant, en utilisant jpa Spring-Data intégré, nous pouvons également le réaliser:

Vous devez simplement utiliser la signature de méthode suivante dans la classe Repository.

ModelClass findBy$Column_1And$Column_2In(Object $col1Value, Object $col2Value );

Selon le schéma, il peut renvoyer une liste ou une seule instance. Cette approche peut être appliquée à une ou plusieurs colonnes, comme indiqué ci-dessus.

Pour votre exemple, cela pourrait être quelque chose comme:

Project findByProjectIdAndProjectNameIn(long projectId, String projectName);

projectId, nomprojet

0
Sudip Bhandari

Vous pouvez utiliser la réponse suggérée par @jombie et:

  • placer l'interface dans un fichier séparé, en dehors de la classe d'entité;
  • utiliser la requête native ou non (le choix dépend de vos besoins);
  • ne substituez pas la méthode findAll() à cette fin, mais utilisez le nom de votre choix;
  • n'oubliez pas de renvoyer un List paramétré avec votre nouvelle interface (par exemple, List<SmallProject>).
0
foxbit

tilisation de la requête native:

Query query = entityManager.createNativeQuery("SELECT projectId, projectName FROM projects");
List result = query.getResultList();
0
ukchaudhary