2017-07-15 2 views
1

J'ai une société de classe @Entity avec plusieurs attributs, référençant une table d'entreprises dans ma base de données. L'un d'entre eux représente une Map companyProperties dans laquelle la table companies est étendue par une table company_properties et les propriétés sont enregistrées au format clé-valeur.JPQL include la carte elementCollection dans l'instruction select

@Entity 
@Table(name = "companies") 
public class Company extends AbstractEntity { 

    private static final String TABLE_NAME = "companies"; 

    @Id 
    @GeneratedValue(generator = TABLE_NAME + SEQUENCE_SUFFIX) 
    @SequenceGenerator(name = TABLE_NAME + SEQUENCE_SUFFIX, sequenceName = TABLE_NAME + SEQUENCE_SUFFIX, allocationSize = SEQUENCE_ALLOCATION_SIZE) 
    private Long id; 

    //some attributes 

    @ElementCollection 
    @CollectionTable(name = "company_properties", joinColumns = @JoinColumn(name = "companyid")) 
    @MapKeyColumn(name = "propname") 
    @Column(name = "propvalue") 
    private Map<String, String> companyProperties; 

    //getters and setters 
} 

Le directeur de l'entité est en mesure d'effectuer correctement trouver des clauses

Company company = entityManager.find(Company.class, companyId); 

Cependant, je ne suis pas en mesure d'effectuer des requêtes JPQL dans cette entité et récupérer la carte en conséquence. Comme l'objet est grand, j'ai juste besoin de sélectionner certains des attributs de ma classe d'entité. Je ne veux pas non plus filtrer par companyProperties mais récupérer tous ceux qui viennent avec la clef étrangère de companyid assignée appropriée. Ce que j'ai essayé de faire est la suivante:

TypedQuery<Company> query = entityManager.createQuery("SELECT c.id, c.name, c.companyProperties " + 
      "FROM Company as c where c.id = :id", Company.class); 
query.setParameter("id", companyId); 
Company result = query.getSingleResult(); 

L'erreur que je reçois est:

java.lang.IllegalArgumentException: Une exception est survenue lors de la création d'une requête dans EntityManager: Exception Description: Problème compilation [ SELECT c.id, c.name, c.compagnieEntreprises FROM Société comme c où c.id =: id]. [21, 40] Le chemin du champ d'état 'c.companyentrepropriétés' ne peut pas être résolu en un type de collection. org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery (EntityManagerImpl.java:1616) org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery (EntityManagerImpl.java:1636) com.sun.enterprise.container .common.impl.EntityManagerWrapper.createQuery (EntityManagerWrapper.java:476)

Essayer de le faire avec des jointures (le plus point que je suis arrivé était avec

Query query = entityManager.createQuery("SELECT c.id, c.name, p " + 
      "FROM Company c LEFT JOIN c.companyProperties p where c.id = :id"); 

ne me donne pas soit les résultats corrects (il renvoie uniquement la valeur de la propriété et non une liste d'entre eux avec la valeur-clé.)

Comment puis-je définir la bonne requête pour cela?

+0

Vous ne pouvez pas inclure d'éléments à valeurs multiples dans la clause de résultat comme n'importe quel document JPQL vous le dirait –

Répondre

1

Votre syntaxe JPA me regarde. Dans votre première requête, vous sélectionnez des champs individuels dans l'entité Company. Mais ce n'est pas ainsi que fonctionne JPA; Lorsque vous interrogez, vous récupérez l'objet entier, avec lequel vous pouvez accéder à n'importe quel champ. Je propose plutôt le code suivant:

TypedQuery<Company> query = entityManager.createQuery("from Company as c where c.id = :id", Company.class); 
query.setParameter("id", companyId); 
Company result = query.getSingleResult(); 

De même, pour la deuxième requête de jointure je suggère le code suivant:

Query query = entityManager.createQuery("SELECT c" + 
     "FROM Company c LEFT JOIN c.companyProperties p WHERE c.id = :id"); 
query.setParameter("id", companyId); 
List<Company> companies = query.getResultList(); 

La raison pour laquelle ne sélectionner qu'une Company et non une entité de propriété est que les propriétés seraient apparaissent comme une collection dans la classe Company. En supposant qu'il existe un un à plusieurs entre les sociétés et les propriétés, vous pouvez accéder aux propriétés de chaque entité Company.

+0

Je ne souhaite pas récupérer l'entité entière mais seulement certains attributs. La raison en est, parce que finalement je vais retourner l'objet à la suite d'un endpoiint de repos. Je ne veux pas que mon client accède à tous les attributs et, au lieu de les mettre à zéro après la requête, je m'attendais à ce que JPQL ne me laisse récupérer que ce dont j'ai besoin –

+0

@SantiagoPerezChavez Puis renvoyez juste ce que vous voulez. Dans tous les cas, même si une entité a des espaces réservés NULL, lorsque vous convertissez en JSON, cela gaspille encore de l'espace. –

+0

Si vous voulez vraiment récupérer uniquement les champs ceetain, alors vous pouvez utiliser une requête SQL native et obtenir un ensemble de résultats constitué de 'Object'. Mais généralement, dans JPA, vous récupérez l'intégralité de l'entité. –

0

Vous vous attendez à obtenir un objet complet Company en sélectionnant uniquement des champs particuliers, ce qui n'est pas possible.Si vous voulez vraiment économiser de la mémoire (qui, dans la plupart des cas ne serait pas beaucoup de succès) et sélectionnez uniquement un champ, vous devez vous attendre un List<Object[]>:

List<Object[]> results = entityManager.createQuery("SELECT c.id, c.name, p " + 
     "FROM Company c LEFT JOIN c.companyProperties p where c.id = :id") 
     .setParameter("id", companyId) 
     .getResultList(); 

Ici, le results contiendra un seul tableau des champs sélectionnés. Vous pouvez utiliser getSingleResult, mais sachez qu'il lancera une exception si aucun résultat n'a été trouvé.