JPA-joindre deux tables dans la classe non-entity

je suis un internaute novice ,essayé de google mais je suis incapable de résoudre ma question. S'il vous plaît aider.

je suis en train de carte de deux entités : la PersonA et Personne dans ma classe POJO PersonC

@Entity
class PersonA{
     String sample_field;
}

@Entity
class Person{
     String id;
     String name;

}

au-dessus de deux sont des entités de jpa.

maintenant je veux les fusionner en une classe de pojo.

class PersonC
{
   Strind id;
   String address;
}

essayé sous le code mais quand j'essaie de récupérer L'adresse / champ de clé étrangère ça ne marche pas.

@SqlResultSetMapping(name="PersonC", 
classes = {
   @ConstructorResult(targetClass = PersonC.class, 
    columns = {@ColumnResult(name="name")
              , @ColumnResult(name="address")
    )}

Où dois-je définir @SqlResultSetMapping ,pour quelle classe de ce qui précède? ) })

11
demandé sur Gunner Barnes 2014-08-07 13:41:11

3 réponses

@SqlResultSetMapping peut être placé à n'importe quelle classe d'entité (ne pas annoter POJOs - ça ne marchera pas). La mise en correspondance avec la classe POJO avec @ConstructorResult a été ajoutée dans la version 2.1 de JPA. POJO utilisé avec la cartographie doit avoir le constructeur correct.

toutes les colonnes correspondant aux arguments du constructeur prévu doivent être spécifiées en utilisant l'élément colonnes de L'annotation ConstructorResult dans le même ordre que celui de l'argument liste du constructeur.

, Veuillez consulter l'exemple suivant avec la requête de l'utilisation et de travailler sur votre dossier en conséquence.

@Entity
public class Address {
    @Id int id;  
    String street;
}


@SqlResultSetMapping(name="PersonDTOMapping",
    classes = {
     @ConstructorResult(targetClass = PersonDTO.class,
       columns = {@ColumnResult(name="name"), @ColumnResult(name="street")}
     )}
)
@Entity
public class Person {
    @Id int id;
    String name;
    Address address;  
}  

public class PersonDTO {
    String name;
    String street;
    public PersonDTO(String name, String street) {
        this.name = name;
        this.street = street;
    }
}

// usage
Query query = em.createNativeQuery(
    "SELECT p.name AS name, a.street AS street FROM Person p, Address a WHERE p.address_id=a.id",
    "PersonDTOMapping");
List<PersonDTO> result = query.getResultList();

veuillez noter que les alias ( AS name et AS street ) doivent correspondre aux noms dans @ColumnResult S. L'exemple a été testé par rapport à Ecliselink 2.5.1.

30
répondu zbig 2015-02-09 14:19:01

Ce post traite de la mise en veille prolongée.

la suggestion de placer le @SqlResultSetMapping et @NamedNativeQuery (ou @NamedQuery ) à l'intérieur de la définition de la classe @Entity n'est pas élégante et ne suit évidemment pas le principe de la séparation des préoccupations.

la solution la plus appropriée est l'utilisation du @MappedSuperclass annotation comme suit:

Singerextend.java (la classe doit être abstrait ):

package pl.music.model.singer.extended;

import javax.persistence.ColumnResult;
import javax.persistence.ConstructorResult;
import javax.persistence.MappedSuperclass;
import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery;
import javax.persistence.SqlResultSetMapping;

@MappedSuperclass
@SqlResultSetMapping( // @formatter:off
    name = "SingerExtendedMapping",
    classes = @ConstructorResult(
        targetClass = SingerExtendedDTO.class,
        columns = {
            @ColumnResult(name = "singer_id", type = Long.class),
            @ColumnResult(name = "first_name"),
            @ColumnResult(name = "last_name"),
            @ColumnResult(name = "count_albums", type = Long.class)
        }
    )
)
@NamedNativeQueries({
    @NamedNativeQuery(
            name = "SingerExtendedAsc",
            query = "select"
                + " singer.singer_id,"
                + " singer.first_name,"
                + " singer.last_name,"
                + " (select count(*) from album where album.singer_id = singer.singer_id) as count_albums"
                + " from singer"
                + " group by singer.singer_id"
                + " order by last_name collate :collation asc, first_name collate :collation asc",
            resultSetMapping = "SingerExtendedMapping"
    )
}) // @formatter:on
public abstract class SingerExtended {
}

puis classe DAO SingerExtendedDAO.java :

package pl.music.model.singer.extended;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class SingerExtendedDAO {

    @PersistenceContext
    EntityManager entityManager;

    @Autowired
    private String collation;

    public List<SingerExtendedDTO> getAll(Integer page, Integer count) {
        TypedQuery<SingerExtendedDTO> query = entityManager.createNamedQuery("SingerExtendedAsc", SingerExtendedDTO.class);
        query.setParameter("collation", collation);
        if ((count != null) && (count.intValue() > 0)) {
            query.setMaxResults(count.intValue());
            if ((page != null) && (page.intValue() >= 0)) {
                query.setFirstResult(count.intValue() * page.intValue());
            }
        }
        List<SingerExtendedDTO> singerExtendedDTOs = query.getResultList();
        return singerExtendedDTOs;
    }

}

et, enfin, la classe DTO .java (vous devez fournir le constructeur" complet"):

package pl.music.model.singer.extended;

public class SingerExtendedDTO {

    private Long singerId;
    private String firstName;
    private String lastName;
    private Long countAlbums;

    // IMPORTANT: this constructor must be defined !!! 
    public SingerExtendedDTO(Long singerId, String firstName, String lastName, Long countAlbums) {
        this.singerId = singerId;
        this.firstName = firstName;
        this.lastName = lastName;
        this.countAlbums = countAlbums;
    }
    ... getters & setters ...
}

Si tout cela est mis en suivant la voie présentée ci-dessus, nous obtenons une solution appropriée:

  • tout est dans un seul paquet,
  • "1519360920 de la requête" déclaration ne pollue pas tout indifférent entité,
  • la séparation des préoccupations est préservée (interrogation séparée+cartographie, DAO et DTO).
2
répondu zinhosky 2018-06-14 09:44:11

vient de trouver une solution un peu plus simple en utilisant JPQL. J'ai volé une partie de l'exemple de @zbig réponse:

@Entity
public class Address {
    @Id int id;  
    String street;
}

@Entity
public class Person {
    @Id int id;
    String name;
    Address address;  
}  

public class PersonDTO {
    String name;
    String street;
    public PersonDTO(String name, String street) {
        this.name = name;
        this.street = street;
    }
}

List<PersonDTO> listOfPersons = em.createQuery("select new com.example.PersonDTO(p.name, a.street) " +
"from Person p, Address a " + 
"WHERE p.address.id=a.id", PersonDTO.class).getResultList();

l'avantage de cette solution est que vous n'avez pas besoin d'utiliser l'annotation @Sqlresulsetmapping, qui doit être placé sur n'importe quelle classe d'entité , pas la classe DTO! Et c'est parfois déroutant parce que la classe entity ne peut être que partiellement liée (en rejoignant plusieurs tables par exemple).

plus d'info ici

1
répondu xagaffar 2018-05-22 14:41:32