Beste Praksis for Mange-Til-Mange Foreninger med Hibernate og JPA

Mange-Til-mange foreninger er en av de mest brukte foreningene MED JPA og Hibernate. Du kan finne mange eksempler for dem i den virkelige verden, og du kan kartlegge dem MED JPA og Hibernate som en uni – eller toveisforening i domenemodellen din.

men du vet sikkert også at disse tilordningene gir flere fallgruver. I denne artikkelen vil jeg vise deg 5 beste praksis som vil hjelpe deg å unngå disse fallgruvene og å implementere effektive mappings. Du vil lære:

  1. Den mest effektive datatypen for din forening
  2. Hvorfor du trenger hjelpemetoder for å administrere din forening
  3. riktig FetchType For en effektiv kartlegging
  4. Når Og hvordan du bruker spørringsspesifikk henting
  5. Cascadetypen du bør unngå for enhver pris

jeg vil ikke dykke inn i detaljene i en grunnleggende mange til mange kartlegging. Hvis du ikke er helt sikker på hvordan du oppretter en slik kartlegging, kan du ta en titt på mange-til-mange-delen i min tilknytnings kartlegging guide.

Den mest effektive datatypen for din forening

YouTube video

de fleste utviklere bruker ikke mye tanker om datatypen til en til-mange forening. De velger bare en java.util.Liste fordi det er enkelt og ikke utfører noen kontroller for å unngå duplikater.

det er OK, hvis du implementerer en Grunnleggende Java-klasse eller hvis du modellerer en en-Til-Mange/Mange-Til-en-forening. Men du bør aldri bruke En Liste hvis du modellerer En mange til mange forening.

@Entitypublic class Book {// DON'T DO THIS!!!@ManyToMany@JoinTable(name = "book_author", joinColumns = { @JoinColumn(name = "fk_book") }, inverseJoinColumns = { @JoinColumn(name = "fk_author") })private List<Author> authors = new ArrayList<Author>();...}

Dvalemodus håndterer fjern operasjoner På mange til Mange relasjoner som er tilordnet til en java.util.Liste svært ineffektivt.

em = emf.createEntityManager();em.getTransaction().begin();// Get Book entity with 2 Authorsb = em.find(Book.class, 1L);// Remove one of the Authorb.getAuthors().remove(a);em.getTransaction().commit();em.close();

den fjerner først alle poster fra tilknytningstabellen før den setter inn alle gjenværende.

09:54:28,876 DEBUG - update Book set title=?, version=? where id=? and version=?09:54:28,878 DEBUG - delete from book_author where fk_book=?09:54:28,882 DEBUG - insert into book_author (fk_book, fk_author) values (?, ?)

du bør i stedet modellere en mange-til-mange-forening som en java.util.Angi.

@Entitypublic class Book {@ManyToMany@JoinTable(name = "book_author", joinColumns = { @JoinColumn(name = "fk_book") }, inverseJoinColumns = { @JoinColumn(name = "fk_author") })private Set<Author> authors = new HashSet<Author>();...}

Hibernate håndterer deretter fjern operasjoner på foreningen mye bedre. Det fjerner nå bare de forventede postene fra foreningen og holder de andre uberørt.

10:00:37,709 DEBUG - update Book set title=?, version=? where id=? and version=?10:00:37,711 DEBUG - delete from book_author where fk_book=? and fk_author=?

Hvorfor du trenger hjelpemetoder for å administrere tilknytningen din

Toveisforeninger tilordnes til et enhetsattributt i begge ender av relasjonene. Så i det forrige eksemplet har du et forfatterattributt på Bokenheten, og et bokattributt på Forfatterenheten. Det gjør implementering AV EN Jpql eller CriteriaQuery veldig behagelig fordi du kan bruke disse attributtene til å definere EN JOIN-setning.

men å legge til eller fjerne en tilknytning blir mer komplisert. Du må alltid utføre endringen i begge ender av foreningen. For Eksempel, hvis Du vil legge Til En Bok Til Forfatter, må du legge den til books-attributtet Til Forfatterenheten, og du må også legge Til Forfatteren forfatterattributtet på Bokenheten. Ellers inneholder din nåværende vedvarende kontekst inkonsekvente data som du vil bruke til slutten av din nåværende transaksjon.

Book b = new Book();b.setTitle("Hibernate Tips - More than 70 solutions to common Hibernate problems");em.persist(b);Author a = em.find(Author.class, 1L);a.getBooks().add(b);b.getAuthors().add(a);

Utility metoder På Forfatter og Bok enheter gjør oppdatering og fjerning mye enklere. I disse metodene utfører du de nødvendige operasjonene på begge enhetene.

@Entitypublic class Author {@ManyToMany(mappedBy = "authors")private Set<Book> books = new HashSet<Book>();...public void addBook(Book book) {this.books.add(book);book.getAuthors().add(this);}public void removeBook(Book book) {this.books.remove(book);book.getAuthors().remove(this);}}

riktig FetchType for en effektiv kartlegging

YouTube-video

Dette er en rask en. Du bør alltid bruke FetchType.LAT for dine mange til mange foreninger. Det forteller din utholdenhet leverandøren ikke å hente de tilknyttede enhetene fra databasen før du bruker dem. Det er vanligvis tilfelle når du ringer sin getter-metode for første gang.

Heldigvis er det standard for alle til-mange foreninger. Så sørg for at du ikke endrer det.

og hvis du vil lære mer OM JPAS forskjellige FetchTypes, vennligst ta en titt på Min Introduksjon til JPA FetchTypes.

når og hvordan du bruker spørringsspesifikk henting

hvis Du bruker FetchType.LAZY, du trenger å vite om spørringsspesifikk henting. Ellers vil søknaden din være veldig treg fordi du opprettet mange n + 1 velg problemer.

YouTube video

Når du laster Inn en enhet og bruker spørringsspesifikk henting, forteller Du Hibernate hvilke tilordnede foreninger den skal initialisere for hver hentet enhet. Den utvider DERETTER select-setningsdelen i spørringen slik at den inneholder kolonnene som er tilordnet av disse andre enhetene, og initialiserer tilknytningene. Og Fordi tilknytningene allerede er initialisert, Trenger Ikke Hibernate å utføre en ekstra spørring når du åpner getter-metoden for første gang.

du kan implementere spørringsspesifikk henting på flere forskjellige måter. Den enkleste er A BLI MED FETCH-klausulen, som jeg vil vise deg her. Men du kan også bruke en @NamedEntityGraph eller En EntityGraph, som jeg forklarte i tidligere artikler.

definisjonen AV EN JOIN FETCH-setning er nesten identisk med en enkel JOIN-setning i EN jpql-spørring. Du trenger bare å legge TIL HENT søkeord.

Author a = em.createQuery("SELECT a FROM Author a JOIN FETCH a.books WHERE a.id = 1", Author.class).getSingleResult();

likevel ser EN JOIN OG EN JOIN FETCH-klausul veldig ut, JOIN FETCH-klausulen HAR en mye større effekt på DEN genererte SQL-spørringen. Det blir ikke bare oversatt til EN SQL JOIN, som det er tilfelle for EN JPQL JOIN-klausul, det tvinger også utholdenhetsleverandøren til å utvide SELECT-klausulen av alle kolonner som er kartlagt av den tilknyttede enheten.

16:21:03,046 DEBUG SQL:94 - select author0_.id as id1_0_0_, book2_.id as id1_1_1_, author0_.firstName as firstNam2_0_0_, author0_.lastName as lastName3_0_0_, author0_.version as version4_0_0_, book2_.format as format2_1_1_, book2_.publishingDate as publishi3_1_1_, book2_.title as title4_1_1_, book2_.version as version5_1_1_, books1_.author_id as author_i2_2_0__, books1_.book_id as book_id1_2_0__ from Author author0_ inner join book_author books1_ on author0_.id=books1_.author_id inner join Book book2_ on books1_.book_id=book2_.id where author0_.id=1

CascadeType du bør unngå for enhver pris

hvis du aktiverer cascading på en tilknytning, bruker vedvarende leverandøren operasjonene du utfører på enheten til alle tilknyttede enheter. Hvis det gjør det for alle operasjoner eller bare for noen få utvalgte, avhenger Av den konfigurerte CascadeType.

YouTube video

det kan høres ut som en fantastisk ide som gjør implementeringen av forretningslogikken mye enklere. Og det er ikke helt galt.

men vennligst unngå CascadeTypes FJERN OG ALLE, som inkluderer FJERN, for mange-til-mange foreninger. I beste fall skaper det bare ytelsesproblemer, men i verste fall kan det også fjerne flere poster enn du hadde tenkt.

jeg forklarte både fallgruvene og deres løsning i flotte detaljer i en tidligere artikkel. Eller hvis du vil holde det enkelt, utløser du den nødvendige informasjonen programmatisk på de tilknyttede enhetene. Dette kan kreve noen flere linjer med kode, men det unngår uventede bivirkninger.

Konklusjon

du kan finne mange eksempler for mange til mange foreninger i den virkelige verden, og du kan enkelt kartlegge dem MED JPA og Hibernate. Dessverre skjuler disse enkle mappingene noen fallgruver som du kan unngå ved å følge disse 5 beste praksisene:

  1. Modellforeninger som java.util.Angi.
  2. Gi hjelpemetoder for å legge til eller fjerne en enhet fra en tilknytning.
  3. bruk Alltid FetchType.LAZY, som er standard, for å unngå ytelsesproblemer.
  4. Bruk spørringsspesifikk henting for å unngå n + 1 velg problemer.
  5. ikke bruk CascadeTypes FJERN OG ALLE.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert.