JPA Bli med Typer

1. Oversikt

I denne opplæringen vil vi se på forskjellige sammenføyningstyper som støttes av JPA.

For det formålet bruker vi JPQL, et spørrespråk for JPA.

2. Eksempel på datamodell

La oss se på eksempeldatamodellen som vi skal bruke i eksemplene.

For det første lager vi en Ansatt enhet:

@Entity offentlig klasse ansatt {@Id @GeneratedValue (strategi = GenerationType.IDENTITY) privat lang id; privat strengnavn; privat alder; @ManyToOne privat avdeling; @OneToMany (mappedBy = "ansatt") private List-telefoner; // getters og setters ...}

Hver Ansatt vil bare bli tildelt en Avdeling:

@Entity public class Department {@Id @GeneratedValue (strategi = GenerationType.AUTO) privat lang id; privat strengnavn; @OneToMany (mappedBy = "avdeling") private List-ansatte; // getters og setters ...}

Til slutt, hver Ansatt vil ha flere Telefons:

@Entity offentlig klasse Telefon {@Id @GeneratedValue (strategi = GenerationType.IDENTITY) privat lang id; privat strengnummer; @ManyToOne privat ansatt ansatt; // getters og setters ...}

3. Indre sammenføyninger

Vi begynner med indre sammenføyninger. Når to eller flere enheter er sammenføyde, samles bare postene som samsvarer med tilknytningstilstanden i resultatet.

3.1. Implisitt indre deltakelse i enkeltverdiforeningens navigasjon

Indre sammenføyninger kan være implisitt. Som navnet tilsier, utvikleren spesifiserer ikke implisitte indre sammenføyninger. Hver gang vi navigerer i en enkeltverdiforening, oppretter JPA automatisk en implisitt sammenkobling:

@Test offentlig ugyldig nårPathExpressionIsUsedForSingleValuedAssociation_thenCreatesImplicitInnerJoin () {TypedQuery query = entityManager.createQuery ("SELECT e.department FROM Employee e", Department.class); Liste resultList = query.getResultList (); // Påstander ...}

Her, den Ansatt enhet har et mange-til-ett forhold til Avdeling enhet. Hvis vi navigerer fra en Ansatt enhet til henne Avdeling - spesifiserer e.avdeling - vi navigerer i en enkelt verdsatt forening. Som et resultat vil JPA opprette en indre sammenføyning. Videre vil sammenføyningsbetingelsen være avledet fra kartlegging av metadata.

3.2. Eksplisitt indre medlemskap med enverdiforening

Deretter skal vi se på eksplisitt indre blir hvor vi bruker JOIN-nøkkelordet i JPQL-spørringen:

@Test offentlig ugyldig nårJoinKeywordIsUsed_thenCreatesExplicitInnerJoin () {TypedQuery query = entityManager.createQuery ("SELECT d FROM Employee e JOIN e.department d", Department.class); Liste resultList = query.getResultList (); // Påstander ...}

I dette spørsmålet, vi spesifiserte et JOIN-nøkkelord og tilhørende Avdeling enhet i FROM-setningenmens de i det forrige ikke ble spesifisert i det hele tatt. Imidlertid, bortsett fra denne syntaktiske forskjellen, vil de resulterende SQL-spørringene være veldig like.

Vi kan også spesifisere et valgfritt INNRE nøkkelord:

@Test offentlig ugyldig nårInnerJoinKeywordIsUsed_thenCreatesExplicitInnerJoin () {TypedQuery query = entityManager.createQuery ("SELECT d FROM Employee e INNER JOIN e.department d", Department.class); Liste resultList = query.getResultList (); // Påstander ...}

Så siden JPA implisitt vil ha en indre sammenføyning, når ville vi trenge å være eksplisitte?

For det første, JPA oppretter en implisitt indre sammenføyning bare når vi spesifiserer et stiuttrykk. For eksempel når vi bare vil velge Ansatts som har en Avdeling og vi bruker ikke et stiuttrykk - e.avdeling -, bør vi bruke JOIN-nøkkelord i spørringen vår.

For det andre, når vi er eksplisitte, kan det være lettere å vite hva som skjer.

3.3. Eksplisitt indre medlemskap med samleverdige foreninger

Et annet sted vi trenger å være eksplisitte er med samleverdige foreninger.

Hvis vi ser på datamodellen vår, er Ansatt har et en-til-mange forhold til Telefon. Som i et tidligere eksempel, kan vi prøve å skrive et lignende spørsmål:

VELG e.telefoner FRA Medarbeider e

Men dette vil ikke helt fungere som kanskje vi hadde tenkt. Siden den valgte foreningen - e.telefoner - er samlingsverdi, vi får en liste over Samlings, i stedet for Telefon enheter:

@Test offentlig ugyldig nårCollectionValuedAssociationIsSpecifiedInSelect_ThenReturnsCollections () {TypedQuery query = entityManager.createQuery ("SELECT e.phones FROM Employee e", Collection.class); Liste resultList = query.getResultList (); // Påstander}

Videre, hvis vi vil filtrere Telefon enheter i WHERE-klausulen, vil ikke JPA tillate det. Dette er fordi et stiuttrykk kan ikke fortsette fra en samlingsverdiforening. Så for eksempel e.phones.nummer er ikke gyldig.

I stedet bør vi opprette en eksplisitt indre sammenføyning og opprette et alias for Telefon enhet. Så kan vi spesifisere Telefon enhet i SELECT- eller WHERE-setningen:

@Test public void whenCollectionValuedAssociationIsJoined_ThenCanSelect () {TypedQuery query = entityManager.createQuery ("SELECT ph FROM Employee e JOIN e.phones ph WHERE ph LIKE '1%" ", Phone.class); Liste resultList = query.getResultList (); // Påstander ...}

4. Ytre sammenføyning

Når to eller flere enheter er sammenføyde, postene som tilfredsstiller tilknytningsbetingelsen, og også postene i den venstre enheten samles i resultatet:

@Test offentlig ugyldig nårLeftKeywordIsSpecified_thenCreatesOuterJoinAndIncludesNonMatched () {TypedQuery query = entityManager.createQuery ("SELECT DISTINCT d From Department d LEFT JOIN d.employees e", Department.class); Liste resultList = query.getResultList (); // Påstander ...}

Her vil resultatet inneholde Avdelings som har assosiert Ansatts og også de som ikke har noen.

Dette blir også referert til som en venstre ytre skjøt. JPA gir ikke rett tilknytning der vi også samler ikke-samsvarende poster fra riktig enhet. Selv om vi kan simulere rett sammenføyning ved å bytte enheter i FROM-klausulen.

5. Blir med i WHERE-klausulen

5.1. Med en tilstand

Vi kan liste opp to enheter i FROM-setningen ogspesifiser deretter sammenføyningsbetingelsen i WHERE-setningen.

Dette kan være nyttig, spesielt når utenlandske nøkler på databasenivå ikke er på plass:

@Test offentlig ugyldig nårEntitiesAreListedInFromAndMatchedInWhere_ThenCreatesJoin () {TypedQuery query = entityManager.createQuery ("VELG d FRA ansatt e, avdeling d WHERE e.department = d", Department.class); Liste resultList = query.getResultList (); // Påstander ...}

Her blir vi med Ansatt og Avdeling enheter, men denne gangen spesifiserer en betingelse i WHERE-klausulen.

5.2. Uten en tilstand (kartesisk produkt)

På samme måte, vi kan liste opp to enheter i FROM-klausulen uten å spesifisere noen tilknytningsbetingelser. I dette tilfellet, vi får et kartesisk produkt tilbake. Dette betyr at hver post i den første enheten er paret med alle andre poster i den andre enheten:

@Test offentlig ugyldig nårEntitiesAreListedInFrom_ThenCreatesCartesianProduct () {TypedQuery query = entityManager.createQuery ("SELECT d FROM Employee e, Department d", Department.class); Liste resultList = query.getResultList (); // Påstander ...}

Som vi kan gjette, vil slike spørsmål ikke fungere bra.

6. Flere sammenføyninger

Så langt har vi brukt to enheter til å utføre sammenføyninger, men dette er ikke en regel. Vi kan også bli med i flere enheter i ett enkelt JPQL-spørsmål:

@Test public void whenMultipleEntitiesAreListedWithJoin_ThenCreatesMultipleJoins () {TypedQuery query = entityManager.createQuery ("SELECT ph FROM Employee e JOIN e.department d JOIN e.phones ph WHERE d.name IS NOT NULL", Phone.cl) Liste resultList = query.getResultList (); // Påstander ...}

Her velger vi alle Telefoner av alle Ansatte som har en Avdeling. I likhet med andre indre sammenføyninger spesifiserer vi ikke forhold siden JPA trekker ut denne informasjonen fra å kartlegge metadata.

7. Hent sammen

La oss nå snakke om hente sammenføyninger. Dens primære bruk er for å hente dovne-assosierte foreninger ivrig etter den aktuelle spørringen.

Her laster vi ivrig inn Ansatts forening:

@Test offentlig ugyldig nårFetchKeywordIsSpecified_ThenCreatesFetchJoin () {TypedQuery query = entityManager.createQuery ("SELECT d FROM Department d JOIN FETCH d.employees", Department.class); Liste resultList = query.getResultList (); // Påstander ...}

Selv om dette spørsmålet ser veldig ut som andre spørsmål, er det en forskjell, og det er det de Ansatts er ivrig lastet. Det betyr at når vi ringer getResultList i testen ovenfor, Avdeling enheter vil ha sitt ansatte feltbelastet, og dermed sparer vi enda en tur til databasen.

Men vær oppmerksom på minneutvekslingen. Vi kan være mer effektive fordi vi bare utførte en forespørsel, men vi lastet også inn alle Avdelings og deres ansatte i minnet med en gang.

Vi kan også utføre den ytre hente sammenføyningen på samme måte som ytre sammenføyninger, der vi samler poster fra den venstre enheten som ikke samsvarer med tilstanden for sammenføyning. Og i tillegg laster den ivrig den angitte tilknytningen:

@Test offentlig ugyldig nårLeftAndFetchKeywordsAreSpecified_ThenCreatesOuterFetchJoin () {TypedQuery query = entityManager.createQuery ("SELECT d FROM Department d LEFT JOIN FETCH d.employees", Department.class); Liste resultList = query.getResultList (); // Påstander ...}

8. Oppsummering

I denne artikkelen har vi dekket JPA-typer.

Som alltid kan du sjekke ut alle prøvene for denne og andre opplæringsprogrammer på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found