JPA-tilslutningstyper

1. Oversigt

I denne vejledning ser vi på forskellige sammenføjningstyper understøttet af JPA.

Til dette formål bruger vi JPQL, et forespørgselssprog til JPA.

2. Prøvedatamodel

Lad os se på vores eksempeldatamodel, som vi bruger i eksemplerne.

For det første opretter vi en Medarbejder enhed:

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

Hver Medarbejder tildeles kun en Afdeling:

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

Endelig hver Medarbejder vil have flere telefons:

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

3. Indvendige sammenføjninger

Vi starter med indre sammenføjninger. Når to eller flere enheder er sammenføjet, samles kun de poster, der matcher tilstanden for sammenføjning i resultatet.

3.1. Implicit indre deltagelse med enkeltværdiforening Navigation

Indvendige sammenføjninger kan være implicit. Som navnet antyder, udvikleren angiver ikke implicitte indre sammenføjninger. Hver gang vi navigerer i en enkeltværdiforening opretter JPA automatisk en implicit sammenkædning:

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

Her, den Medarbejder enhed har et mange-til-en forhold til Afdeling enhed. Hvis vi navigerer fra en Medarbejder enhed til hende Afdeling - specificerer e.afdeling - vi navigerer i en enkeltværdiforening. Som et resultat opretter JPA en indre sammenføjning. Desuden vil sammenføjningsbetingelsen blive afledt af kortlægning af metadata.

3.2. Eksplicit indre tilslutning til en enkeltværdiforening

Dernæst ser vi på eksplicit indre sammenføjninger hvor vi bruger JOIN-nøgleordet i vores JPQL-forespørgsel:

@Test offentligt ugyldigt nårJoinKeywordIsUsed_thenCreatesExplicitInnerJoin () {TypedQuery query = entityManager.createQuery ("VÆLG d FRA medarbejder e JOIN e.department d", Department.class); Liste resultList = query.getResultList (); // Påstande ...}

I denne forespørgsel vi specificerede et JOIN-nøgleord og det tilknyttede Afdeling enhed i FROM-klausulen, mens de i det foregående slet ikke var specificeret. Men bortset fra denne syntaktiske forskel, vil de resulterende SQL-forespørgsler være meget ens.

Vi kan også angive et valgfrit INNRE nøgleord:

@Test offentlig ugyldig nårInnerJoinKeywordIsUsed_thenCreatesExplicitInnerJoin () {TypedQuery forespørgsel = entityManager.createQuery ("VÆLG d FRA medarbejder e INNER JOIN e.department d", Department.class); Liste resultList = query.getResultList (); // Påstande ...}

Så da JPA implicit vil have en indre sammenføjning, hvornår skal vi være eksplicitte?

For det første, JPA opretter kun en implicit indre sammenføjning, når vi angiver et stiudtryk. For eksempel når vi kun vil vælge Medarbejders der har en Afdeling og vi bruger ikke et stiudtryk - e.afdeling -, skal vi bruge JOIN nøgleord i vores forespørgsel.

For det andet, når vi er eksplicitte, kan det være lettere at vide, hvad der foregår.

3.3. Eksplicit indre deltagelse med sammenslutningsværdige foreninger

Et andet sted vi er nødt til at være eksplicit, når det gælder samlinger, der er værdifulde.

Hvis vi ser på vores datamodel, er Medarbejder har et en-til-mange forhold til telefon. Som i et tidligere eksempel kan vi prøve at skrive en lignende forespørgsel:

VÆLG e.phones fra medarbejder e

Men dette fungerer ikke helt som vi måske havde tænkt os. Siden den valgte forening - e.telefoner - er samlingsværdi vi får en liste over Kollektions, i stedet for telefon enheder:

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

Desuden, hvis vi vil filtrere telefon enheder i WHERE-klausulen, tillader JPA det ikke. Dette er fordi et stiudtryk kan ikke fortsætte fra en samlingsværdiforening. Så for eksempel e.phones.nummer er ikke gyldig.

I stedet skal vi oprette en eksplicit indre sammenføjning og oprette et alias for telefon enhed. Så kan vi specificere telefon enhed i SELECT- eller WHERE-klausulen:

@Test offentlig ugyldig nårCollectionValuedAssociationIsJoined_ThenCanSelect () {TypedQuery forespørgsel = entityManager.createQuery ("VÆLG ph fra medarbejder e JOIN e.phones ph WHERE ph LIKE '1%'", Phone.class); Liste resultList = query.getResultList (); // Påstande ...}

4. Ydre samling

Når to eller flere enheder er sammenføjet udvendigt, de poster, der opfylder tilslutningsbetingelsen, og også poster i den venstre enhed er samlet i resultatet:

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

Her vil resultatet indeholde Afdelings, der har tilknyttet Medarbejders og også dem, der ikke har nogen.

Dette kaldes også en venstre ydre sammenføjning. JPA giver ikke rigtige sammenføjninger hvor vi også indsamler ikke-matchende poster fra den rigtige enhed. Selvom vi kan simulere rigtige sammenføjninger ved at bytte enheder i FROM-klausulen.

5. Tilslutter sig WHERE-klausulen

5.1. Med en betingelse

Vi kan liste to enheder i FROM-klausulen ogangiv derefter sammenføjningsbetingelsen i WHERE-klausulen.

Dette kan være praktisk, især når udenlandske nøgler på databaseniveau ikke er på plads:

@Test offentlig ugyldig nårEntitiesAreListedInFromAndMatchedInWhere_ThenCreatesJoin () {TypedQuery forespørgsel = entityManager.createQuery ("VÆLG d FRA medarbejder e, afdeling d HVOR e.department = d", Department.class); Liste resultList = query.getResultList (); // Påstande ...}

Her deltager vi Medarbejder og Afdeling enheder, men denne gang angiver en betingelse i WHERE-klausulen.

5.2. Uden en betingelse (kartesisk produkt)

Tilsvarende Vi kan angive to enheder i FROM-klausulen uden at angive nogen tilslutningsbetingelser. I dette tilfælde, vi får et kartesisk produkt tilbage. Dette betyder, at hver post i den første enhed er parret med alle andre poster i den anden enhed:

@Test offentlig ugyldig nårEntitiesAreListedInFrom_ThenCreatesCartesianProduct () {TypedQuery forespørgsel = entityManager.createQuery ("VÆLG d FRA medarbejder e, Afdeling d", Department.class); Liste resultList = query.getResultList (); // Påstande ...}

Som vi kan gætte, fungerer disse slags forespørgsler ikke godt.

6. Flere sammenføjninger

Indtil videre har vi brugt to enheder til at udføre sammenføjninger, men dette er ikke en regel. Vi kan også deltage i flere enheder i en enkelt JPQL-forespørgsel:

@Test offentlig ugyldig nårMultipleEntitiesAreListedWithJoin_ThenCreatesMultipleJoins () {TypedQuery forespørgsel = entityManager.createQuery ("VÆLG ph fra medarbejder e JOIN e.department d JOIN e.phones ph WHERE d.name IS NOT NULL", Phone.cl Liste resultList = query.getResultList (); // Påstande ...}

Her vælger vi alle Telefoner Af alle Medarbejdere der har en Afdeling. I lighed med andre indre sammenføjninger specificerer vi ikke betingelser, da JPA udtrækker disse oplysninger fra kortlægning af metadata.

7. Hent sammenføjninger

Lad os nu tale om hente sammenføjninger. Dens primære anvendelse er til at hente dovne-associerede foreninger ivrigt til den aktuelle forespørgsel.

Her indlæser vi ivrigt Medarbejders forening:

@Test offentlig ugyldig nårFetchKeywordIsSpecified_ThenCreatesFetchJoin () {TypedQuery forespørgsel = entityManager.createQuery ("VÆLG d FRA afdeling d JOIN FETCH d.medarbejdere", Department.class); Liste resultList = query.getResultList (); // Påstande ...}

Selvom denne forespørgsel ligner meget andre forespørgsler, er der en forskel, og det er den det Medarbejders er ivrig lastet. Det betyder, at når vi først ringer getResultList i testen ovenfor, Afdeling enheder vil have deres medarbejdere feltindlæst, hvilket sparer os endnu en tur til databasen.

Men vær opmærksom på hukommelsen. Vi kan være mere effektive, fordi vi kun udførte en forespørgsel, men vi indlæste også alle Afdelings og deres medarbejdere i hukommelsen på en gang.

Vi kan også udføre den ydre hentningssamling på samme måde som ydre sammenføjninger, hvor vi indsamler poster fra den venstre enhed, der ikke matcher sammenkædningsbetingelsen. Og derudover indlæser den ivrigt den angivne tilknytning:

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

8. Resume

I denne artikel har vi dækket JPA-tilslutningstyper.

Som altid kan du tjekke alle prøverne til denne og andre selvstudier på GitHub.


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