Programmēšana

Java neatlaidība ar JPA un hibernātu, 2. daļa: Daudzas pret daudziem attiecības

Šīs apmācības pirmajā pusē tika ievadīti Java Noturības API pamati un parādīts, kā konfigurēt JPA lietojumprogrammu, izmantojot hibernācijas 5.3.6 un Java 8. Ja esat izlasījis šo apmācību un izpētījis tās piemēru, tad jūs zināt JPA entītiju un daudzu savstarpējo attiecību modelēšana JPA. Jums ir bijusi arī prakse rakstīt nosauktus vaicājumus ar JPA vaicājumu valodu (JPQL).

Šajā apmācības otrajā pusē mēs iedziļināsimies JPA un hibernācijas režīmā. Jūs uzzināsiet, kā modelēt attiecības starp daudziem pret daudziem Filma un SuperHero entītijām, izveidojiet šīm entītijām atsevišķus krātuves un saglabājiet entītijas H2 atmiņas datu bāzē. Jūs arī uzzināsiet vairāk par kaskādes darbību nozīmi JPA un saņemsiet padomus a CascadeType stratēģija datu bāzē esošajām vienībām. Visbeidzot, mēs apkoposim darbojošos lietojumprogrammu, kuru varat palaist IDE vai komandrindā.

Šajā apmācībā galvenā uzmanība tiek pievērsta JPA pamatiem, taču noteikti pārbaudiet šos Java padomus, ieviešot progresīvākas tēmas JPA:

  • Mantojuma attiecības JPA un hibernātā
  • Saliktie taustiņi JPA un hibernācijas režīmā
lejupielādēt Iegūt kodu Lejupielādējiet avota kodu, piemēram, šajā apmācībā izmantotajām lietojumprogrammām. Izveidoja Steven Haines JavaWorld.

Daudzas pret daudziem attiecības JPA

Daudzas pret daudzām attiecības definējiet entītijas, kurām abām attiecību pusēm var būt vairākas atsauces uz otru. Piemēram, mēs veidosim filmas un supervaroņus. Atšķirībā no autoru un grāmatu 1. daļas piemēra, filmai var būt vairāki supervaroņi, un supervaronis var parādīties vairākās filmās. Mūsu supervaroņi - Ironman un Thor - abi parādās divās filmās: "The Avengers" un "Avengers: Infinity War".

Lai modelētu šīs attiecības pret daudziem, izmantojot JPA, mums būs nepieciešamas trīs tabulas:

  • FILMA
  • SUPER_HERO
  • SUPERHERO_MOVIES

1. attēlā parādīts domēna modelis ar trim tabulām.

Stīvens Heinss

Pieraksti to SuperHero_Filmas ir pievienoties galdam starp Filma un SuperHero tabulas. Apvienotajā parlamentārajā asamblejā pievienošanās galds ir īpaša veida galds, kas atvieglo attiecības starp daudziem pret daudziem.

Vienvirziena vai divvirzienu?

JPA mēs izmantojam @ManyToMany anotācija, lai modelētu attiecības starp daudziem. Šāda veida attiecības var būt vienvirziena vai divvirzienu:

  • Iekšā vienvirziena attiecības tikai viena attiecībās esoša vienība norāda otru.
  • Iekšā divvirzienu attiecības abas entītijas norāda viena uz otru.

Mūsu piemērs ir divvirzienu, tas nozīmē, ka filma norāda uz visiem tās varoņiem un supervaronis norāda uz visām viņu filmām. Divvirzienu attiecībās “viens pret daudziem” viens subjekts pieder attiecības un otra ir kartēts ar attiecibas. Mēs izmantojam kartētsPēc atribūts @ManyToMany anotācija, lai izveidotu šo kartēšanu.

1. sarakstā ir redzams programmas avota kods SuperHero klasē.

Sarakstā 1. SuperHero.java

 pakete com.geekcap.javaworld.jpa.model; importēt javax.persistence.CascadeType; importēt javax.persistence.Entity; importēt javax.persistence.FetchType; importēt javax.persistence.GeneratedValue; importēt javax.persistence.Id; importēt javax.persistence.JoinColumn; importēt javax.persistence.JoinTable; importēt javax.persistence.ManyToMany; importēt javax.persistence.Table; importēt java.util.HashSet; importēt java.util.Set; importēt java.util.stream.Collectors; @Entity @Table (name = "SUPER_HERO") publiskās klases supervaronis {@Id @GeneratedValue private Integer id; privāts virknes nosaukums; @ManyToMany (fetch = FetchType.EAGER, cascade = CascadeType.PERSIST) @JoinTable (name = "SuperHero_Movies", joinColumns = {@JoinColumn (name = "superhero_id")}}, inverseJoinColumns = {@JoinColumn (name = }) private Set movies = new HashSet (); public SuperHero () {} public SuperHero (Integer id, String name) {this.id = id; this.name = nosaukums; } publiskais supervaronis (virknes nosaukums) {this.name = name; } public Integer getId () {return ID; } public void setId (Integer id) {this.id = id; } public String getName () {atgriešanās nosaukums; } public void setName (virknes nosaukums) {this.name = name; } public Set getMovies () {atgriešanās filmas; } @Orride public String toString () {return "SuperHero {" + "id =" + id + ", + name +" \ '' + ", + movies.stream (). Map (Movie :: getTitle) .collect (Collectors.toList ()) + "\ '' + '}'; }} 

The SuperHero klasē ir pāris anotācijas, kurām vajadzētu būt pazīstamām no 1. daļas:

  • @Entity identificē SuperHero kā APA vienība.
  • @Tabula kartē SuperHero entītiju tabulā "SUPER_HERO".

Ņemiet vērā arī Vesels skaitlisid lauks, kas norāda, ka tabulas galvenā atslēga tiks automātiski ģenerēta.

Tālāk mēs apskatīsim @ManyToMany un @JoinTable anotācijas.

Stratēģiju ienešana

Lieta, ko pamanīt @ManyToMany anotācija ir tā, kā mēs konfigurējam ienesšanas stratēģija, kas var būt slinks vai vēlas. Šajā gadījumā mēs esam iestatījuši atnest uz VĒLĒTĀJS, tā, ka tad, kad mēs iegūstam a SuperHero no datu bāzes mēs arī automātiski izgūsim visu atbilstošo Filmas.

Ja mēs izvēlētos izpildīt a Slinkums atnest, mēs tikai izgūtu katru Filma jo tas bija īpaši pieejams. Slinki ielādēt ir iespējams tikai tad, kad SuperHero ir pievienots EntityManager; pretējā gadījumā piekļuve supervaroņa filmām radīs izņēmumu. Mēs vēlamies, lai pēc pieprasījuma varētu piekļūt supervaroņa filmām, tāpēc šajā gadījumā mēs izvēlamies VĒLĒTĀJS ienesšanas stratēģija.

CascadeType.PERSIST

Kaskādes operācijas definējiet, kā supervaroņi un viņu filmas tiek saglabāti datu bāzē un no tās. Ir vairākas kaskādes tipa konfigurācijas, no kurām izvēlēties, un par tām mēs vairāk runāsim vēlāk šajā apmācībā. Pagaidām vienkārši ņemiet vērā, ka esam iestatījuši kaskāde atribūts CascadeType.PERSIST, kas nozīmē, ka, saglabājot supervaroni, tiks saglabātas arī tā filmas.

Pievienojieties galdiem

JoinTable ir klase, kas atvieglo attiecības starp daudziem pret daudziem SuperHero un Filma. Šajā klasē mēs definējam tabulu, kurā tiks glabātas abas galvenās atslēgas SuperHero un Filma vienības.

1. saraksts norāda, ka tabulas nosaukums būs SuperHero_Filmas. The pievienoties kolonnai būs superhero_idun apgrieztā savienojuma kolonna būs movie_id. The SuperHero vienībai pieder attiecības, tāpēc kolonnā Pievienoties tiks aizpildīta SuperHerogalvenā atslēga. Kolonnā Apgrieztā pievienošanās tiek norādīts uz entītiju attiecību otrā pusē, kas ir Filma.

Pamatojoties uz šīm 1. saraksta definīcijām, mēs sagaidām, ka tiks izveidota jauna tabula ar nosaukumu SuperHero_Filmas. Tabulā būs divas kolonnas: superhero_id, kas atsaucas uz id kolonna SUPERHERO tabula un movie_id, kas atsaucas uz id kolonna FILMA tabula.

Filmu klase

2. Sarakstā ir redzams Filma klasē. Atgādināsim, ka divvirzienu attiecībās attiecības pieder vienai vienībai (šajā gadījumā SuperHero), kamēr otrs ir attēlots attiecībās. Kods 2 sarakstā ietver attiecību kartēšanu, kas tiek piemērota Filma klasē.

Saraksts 2. Movie.java

 pakete com.geekcap.javaworld.jpa.model; importēt javax.persistence.CascadeType; importēt javax.persistence.Entity; importēt javax.persistence.FetchType; importēt javax.persistence.GeneratedValue; importēt javax.persistence.Id; importēt javax.persistence.ManyToMany; importēt javax.persistence.Table; importēt java.util.HashSet; importēt java.util.Set; @Entity @Table (name = "MOVIE") public class Movie {@Id @GeneratedValue private Integer id; privāts stīgu nosaukums; @ManyToMany (mappedBy = "filmas", kaskāde = CascadeType.PERSIST, fetch = FetchType.EAGER) privāts Set superHeroes = jauns HashSet (); publiskā filma () {} publiskā filma (vesels skaitlis, virknes nosaukums) {this.id = id; this.title = nosaukums; } publiskā filma (virknes nosaukums) {this.title = title; } public Integer getId () {return ID; } public void setId (Integer id) {this.id = id; } public String getTitle () {atgriešanās nosaukums; } public void setTitle (virknes nosaukums) {this.title = nosaukums; } public set getSuperHeroes () {return superHeroes; } public void addSuperHero (SuperHero superHero) {superHeroes.add (superHero); superHero.getMovies (). pievienot (šo); } @Orride public String toString () {return "Filma {" + "id =" + id + ", + title +" \ '' + '}'; }}

Šim īpašumam tiek izmantotas šādas īpašības @ManyToMany anotācija 2. sarakstā:

  • kartētsPēc atsauces uz lauka nosaukumu uz SuperHero klase, kas pārvalda attiecības pret daudziem. Šajā gadījumā tas atsaucas uz filmas lauks, kuru mēs definējām 1. sarakstā ar atbilstošo JoinTable.
  • kaskāde ir konfigurēts CascadeType.PERSIST, kas nozīmē, ka tad, kad a Filma tiek saglabāts atbilstošais SuperHero būtu jāsaglabā arī vienības.
  • atnest stāsta EntityManager ka tai būtu jāatgūst filmas supervaroņi dedzīgi: kad tas ielādējas a Filma, tam vajadzētu ielādēt arī visus atbilstošos SuperHero vienības.

Kaut kas cits, kas jāatzīmē par Filma klase ir tā addSuperHero () metodi.

Konfigurējot entītijas noturībai, nepietiek tikai ar supervaroņa pievienošanu filmai; mums jāatjaunina arī otra attiecību puse. Tas nozīmē, ka mums filma jāpievieno supervaronim. Kad abas attiecību puses ir pareizi konfigurētas tā, ka filmai ir atsauce uz supervaroni un supervaronim ir atsauce uz filmu, tad arī pievienošanās tabula būs pareizi aizpildīta.

Mēs esam definējuši abas savas entītijas. Tagad apskatīsim krātuves, kuras izmantosim, lai tās saglabātu datu bāzē un no tās.

Padoms! Uzstādiet abas galda puses

Bieža kļūda ir iestatīt tikai vienu attiecību pusi, saglabāt entītiju un pēc tam novērot, ka pievienošanās tabula ir tukša. Nosakot abas attiecību puses, tas tiks novērsts.

JPA krātuves

Mēs varētu ieviest visu mūsu noturības kodu tieši lietojumprogrammas paraugā, taču, izveidojot repozitorija klases, mēs varam nodalīt noturības kodu no lietojumprogrammas koda. Tāpat kā mēs to darījām ar grāmatu un autoru lietojumprogrammu 1. daļā, mēs izveidosim EntityManager un pēc tam izmantojiet to, lai inicializētu divus krātuves, vienu katrai entītijai, kuru mēs pastāvam.

3. sarakstā ir redzams MovieRepository klasē.

Saraksts 3. MovieRepository.java

 pakete com.geekcap.javaworld.jpa.repository; importēt com.geekcap.javaworld.jpa.model.Filma; importēt javax.persistence.EntityManager; importēt java.util.List; importēt java.util.Papildu; publiskā klase MovieRepository {private EntityManager entityManager; public MovieRepository (EntityManager entityManager) {this.entityManager = entityManager; } public Izvēles izvēles saglabāšana (Filmas filma) {mēģiniet {entityManager.getTransaction (). sākt (); entityManager.persist (filma); entityManager.getTransaction (). izdarīt (); atgriezties pēc izvēles (filma); } catch (izņēmums e) {e.printStackTrace (); } atgriešanās Optional.empty (); } public Izvēles findById (Integer id) {Movie movie = entityManager.find (Movie.class, id); atgriešanās filma! = null? Neobligāts (filmai): Neobligāti. Tukšs (); } public List findAll () {return entityManager.createQuery ("from Movie"). getResultList (); } public void deleteById (Integer id) {// Ielādēt filmu ar šo ID Movie movie = entityManager.find (Movie.class, id); if (filma! = null) {mēģiniet {// Sākt darījumu, jo mēs mainīsim datu bāzes entītijuManager.getTransaction (). begin (); // Noņemiet visas supervaroņu atsauces uz šo filmu movie.getSuperHeroes (). ForEach (superHero -> {superHero.getMovies (). Noņemt (filma);}); // Tagad noņemiet filmas entītijuManager.remove (movie); // Izpildiet darījuma entītijuManager.getTransaction (). Saistības (); } catch (izņēmums e) {e.printStackTrace (); }}}} 

The MovieRepository tiek inicializēts ar EntityManager, tad to saglabā dalībnieka mainīgajā, lai izmantotu tā noturības metodēs. Mēs apsvērsim katru no šīm metodēm.

Noturības metodes

Pārskatīsim MovieRepositoryun noturības metodes un redzēt, kā tās mijiedarbojas ar EntityManagernoturības metodes.

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