Java >> Java tutorial >  >> Tag >> hibernate

Hibernates ResultTransformer i Hibernate 4, 5 og 6

Hibernate implementerer JPAs standardiserede konstruktørudtryk og @SqlResultSetMappings for at kortlægge resultaterne af dine forespørgsler. Og det understøtter også proprietære ResultTransformers. De giver en kraftfuld og fleksibel måde at kortlægge resultatet af din JPQL, Criteria og native SQL-forespørgsel til en specifik objektstruktur. Dette kan være entitets- eller DTO-objekter, java.util.List eller java.util.Map repræsentationer af hver post eller en tilpasset datastruktur.

Resultattransformere var især populære med Hibernate 4, men blev forældet i Hibernate 5. Desværre giver Hibernate 5 ikke et alternativ til dem. På grund af det kan det se ud som ResultTransformer ville blive fjernet i Hibernate 6. Men det er ikke tilfældet!

Hibernate 6 vil give en forbedret version af ResultTranformers baseret på 2 funktionelle grænseflader. Baseret på den aktuelle kode i Hibernate 6-lageret, migrering af din eksisterende ResultTransformer burde ikke være en stor sag.

ResultTransformer i Hibernate 4 og 5

Hibernate 4 og 5 inkluderer flere indbyggede ResultTransformer . Derudover kan du levere dine egne implementeringer. Men før vi taler om de forskellige ResultTransformers , lad mig vise dig, hvordan du anvender dem på din forespørgsel.

Du behøver kun at angive en forekomst af din ResultTransformer til setResultTransformer metode til Hibernates Forespørgsel interface. Hvis du bruger JPA's EntityManager og Forespørgsel interface, skal du pakke dem ud. Hvis du pakker EntityManager ud , får du den tilknyttede Hibernate Session . Hvis du pakker JPA's Forespørgsel ud interface, får du Hibernates Forespørgsel interface. Jeg forklarede det mere detaljeret i Hibernate Tip:Sådan får du adgang til Hibernate API'er fra JPA.

OK, lad os tage et kig på nogle af de almindeligt anvendte ResultTransformers i Hibernate 4 og 5.

AliasToBeanResultTransformer

JPA giver dig mulighed for at knytte hver post i dit forespørgselsresultat til et ikke-administreret DTO-objekt. Du kan definere disse tilknytninger ved hjælp af et konstruktørudtryk i JPQL eller et @ConstructorResult for native forespørgsler. Begge disse muligheder kræver, at du tilføjer en konstruktør til din DTO-klasse, der angiver alle attributter. Dette kan være problematisk, hvis din DTO-klasse har et stort antal attributter.

Hibernates AliasToBeanResultTransformer giver en anden måde baseret på bønnespecifikationen. Den bruger standardkonstruktøren af ​​DTO-klassen til at instansiere et nyt objekt. I det næste trin bruger Hibernate refleksion til at kalde en seter-metode for hver aliasværdi i forespørgslen. Det gør det velegnet til DTO'er, der er implementeret som en standard Java-klasse, men ikke som en Java-record.

Query query = session.createQuery("select p.id as personId,p.firstName as firstName, p.lastName as lastName from Person p")
    .setResultTransformer(new AliasToBeanResultTransformer(PersonDTO.class));
List<PersonDTO> personDTOS = query.list();

I dette eksempel er AliasToBeanResultTransformer bruger standardkonstruktøren til at instansiere en ny PersonDTO objekt for hver post, der returneres af forespørgslen. I det næste trin kalder Hibernate metoderne setPersonId , setFirstName, og setLastName med de værdier, der returneres af forespørgslen.

ToListResultTransformer og AliasToEntityMapResultTransformer

Hvis du ikke ønsker at ændre de valgte data og ikke har en matchende DTO-klasse, kan du bruge Hibernates ToListResultTransformer eller AliasToEntityMapResultTransformer . ToListResultTransformer kortlægger Objektet[] returneres af din forespørgsel med alle dens elementer til en java.util.List . AliasToEntityMapResultTransformer transformerer forespørgselsresultatet til et java.util.Map der indeholder alle aliasede værdier af resultatsættet. Aliaset for hver værdi bruges som nøglen til Kort .

Her kan du se et eksempel på AliasToEntityMapResultTransformer . Du kan bruge ToListResultTransformer på samme måde.

Query selectPerson = session.createQuery(
    "Select p.id as id, " +
    "p.firstName as firstName, " +
    "p.lastName as lastName " +
    "from Person p")
    .setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
List<Map> list = selectPerson.list();

Implementering af din egen ResultTransformer

Hvis du ønsker at implementere din egen ResultTransformer med Hibernate 4 eller 5 skal du implementere Hibernates ResultTransformer interface. Denne grænseflade definerer 2 metoder:transformTuplen og transformlisten metoder.

En almindelig ResultTransformer implementering implementerer kortlægningen af ​​hver post i transformTuple metode. transformlisten metoden returnerer kun den medfølgende liste over tupler.

Jeg bruger den tilgang i følgende kodestykke til at implementere min egen ResultTransformer der knytter hver post til en PersonDTO objekt.

Query query = session.createNativeQuery("select id as personId, first_name as firstName, last_name as lastName, city from Person p")
    .setResultTransformer(new ResultTransformer(){
            @Override
            public Object transformTuple(Object[] tuples, String[] aliases) {
                PersonDTO personDTO = new PersonDTO();
                personDTO.setPersonId((int)tuples[0]);
                personDTO.setFirstName((String)tuples[1]);
                personDTO.setLastName((String)tuples[2]);
                return personDTO;
            }
 
            @Override
            public List transformList(List list) {
                return list;
            }
        });
List<PersonDTO> list = query.list();

ResultTransformer i Hibernate 6

Da jeg beskrev implementeringen af ​​en brugerdefineret ResultTransformer i Hibernate 4 og 5 nævnte jeg også en af ​​ulemperne ved ResultTransformer interface. Den definerer transformTuplen og transformliste metoder, som begge skal implementeres. De fleste applikationer implementerer kun 1 af disse 2 metoder på en meningsfuld måde. Men fordi begge metoder er en del af grænsefladedefinitionen, skal du implementere dem begge og kan ikke bruge ResultTransformer som en funktionel grænseflade i lambda-udtryk.

Dette ændrede sig i Hibernate 6. Hibernate-teamet har opdelt ResultTransformer grænseflade til de 2 funktionelle grænseflader:TupleTransformer og ResultListTransformer . Du kan indstille dem ved at kalde setTupleTransformer og setResultListTransformer metoder på Hibernates Forespørgsel grænseflade.

Hibernate-teamet konverterede også ResultTransformer implementeringer leveret af Hibernate 4 og 5 til TupleTransformer eller ResultListTransformer implementeringer i Hibernate 6. Derfor bør de nødvendige ændringer ved migrering af din applikation til Hibernate 6 være minimale.

Query query = session.createQuery("select p.id as personId,p.firstName as firstName, p.lastName as lastName from Person p")
    .setTupleTransformer(new AliasToBeanResultTransformer<PersonDTO>(PersonDTO.class)).getSingleResult();
List<PersonDTO> personDTOS = query.list();

Og som du kan se i det følgende kodestykke, er implementeringen af ​​en brugerdefineret transformer i Hibernate 6 meget mere kortfattet.

PersonDTO person = (PersonDTO) session
        .createQuery("select id as personId, first_name as firstName, last_name as lastName, city from Person p", Object[].class)
        .setTupleTransformer((tuples, aliases) -> {
                log.info("Transform tuple");
                PersonDTO personDTO = new PersonDTO();
                personDTO.setPersonId((int)tuples[0]);
                personDTO.setFirstName((String)tuples[1]);
                personDTO.setLastName((String)tuples[2]);
                return personDTO;
        }).getSingleResult();

Konklusion

Hibernates ResultTransformers give forskellige måder at kortlægge resultatet af din forespørgsel til forskellige datastrukturer. De blev almindeligvis brugt i Hibernate 4, blev forældet i Hibernate 5 og blev erstattet af de funktionelle grænseflader TupleTransformer og ResultListTransformer i Hibernate 6.

Den følgende liste viser de 3 mest brugte ResultTransformer s i Hibernate 4 og 5. Disse er stadig tilgængelige i Hibernate 6 og implementerer nu TupleTransformer og/eller ResultListTransformer grænseflader.

  • AliasToBeanResultTransformer – Instantierer og indstiller attributter på DTO-objekter baseret på det alias, der er defineret i forespørgslen.
  • ToListResultTransformer – Knytter hver post i forespørgselsresultatet til en java.util.List .
  • AliasToEntityMapResultTransformer – Tilordner aliasværdierne for hver post i forespørgselsresultatet til et java.util.Map.

Du kan også implementere din egen transformation:

  • I Hibernate 4 og 5 skal du implementere ResultTransformer interface og håndtere kortlægningen af ​​hver resultatsætpost i transformTuple metode.
  • I Hibernate 6 skal du implementere de funktionelle grænseflader TupleTransformer eller ResultListTransformer .

Java tag