Interogarea entităților JPA cu JPQL și SQL nativ

exemplu de aplicație

fragmentele de cod discutate în articol sunt preluate din fișierele sursă Java utilizate în aplicația eșantion care însoțește articolul. Privind prin arhiva eșantion, este posibil să observați că aceasta este o aplicație Web simplă bazată pe tehnologiile Java Servlet și Java Persistence API. Pentru simplitate, nu folosește Enterprise beans, emitând interogări JPQL direct din servleturi. Aceasta nu înseamnă, totuși, că nu veți putea utiliza interogările JPQL discutate aici în Enterprise beans—puteți defini interogări JPQL în orice componente Java EE.

Figura 1 ilustrează structura entităților eșantionului. După cum puteți vedea, conține un set de entități legate între ele cu relații de diferite tipuri. O astfel de structură ramificată este necesară pentru a ilustra utilizarea interogărilor JPQL join discutate în definirea secțiunii JPQL Joins mai târziu în articol.

Figura 1 Relațiile dintre entitățile utilizate în cadrul aplicației eșantion

pentru o instrucțiune detaliată cu privire la modul de configurare și apoi lansarea aplicației eșantion, puteți consulta readme.fișier txt în directorul rădăcină al arhivei eșantion.

utilizarea JPQL în aplicațiile Java EE

dacă aveți experiență practică cu bazele de date, cel mai probabil v-ați udat deja picioarele cu SQL, instrumentul standard care oferă un set de instrucțiuni pentru accesarea și manipularea informațiilor din bazele de date relaționale. De fapt, există multe asemănări între JPQL și SQL. Ambele sunt utilizate pentru a accesa și manipula datele bazei de date, pe termen lung. Și ambele folosesc declarații nonprocedurale-comenzi recunoscute de un interpret special. În plus, JPQL este similar cu SQL în sintaxa sa.

principala diferență dintre JPQL și SQL constă în faptul că primul se ocupă de entitățile JPA, în timp ce acesta din urmă se ocupă direct de datele relaționale. Ca un dezvoltator Java, de asemenea, poate interesat să afle că folosind JPQL, spre deosebire de SQL/JDBC, elimină necesitatea de a utiliza JDBC API din codul Java—containerul face toate acestea de lucru pentru tine în spatele scenei.

JPQL vă permite să definiți interogări utilizând una dintre următoarele trei instrucțiuni: selectare, Actualizare sau ștergere. Este interesant de observat că interfața API EntityManager oferă metode care pot fi utilizate și pentru a efectua operațiuni de preluare, actualizare și ștergere a entităților. În special, acestea sunt metode de găsire, îmbinare și eliminare. Cu toate acestea, utilizarea acestor metode este de obicei limitată la o singură instanță de entitate, cu excepția cazului în care cascada are efect, desigur. În schimb, declarațiile JPQL nu au o astfel de limitare—puteți defini operațiunile de actualizare și ștergere în bloc peste seturi de entități și puteți defini interogări care returnează seturi de instanțe de entități.

pentru a emite o interogare JPQL din Codul Java, trebuie să utilizați metodele adecvate ale API EntityManager și API Query, efectuând următorii pași generali:

  • 1. Obțineți o instanță de EntityManager, utilizând injecția sau în mod explicit printr-o instanță EntityManagerFactory.
  • 2. Creați o instanță de interogare prin invocarea unei metode EntityManager corespunzătoare, cum ar fi createQuery.
  • 3. Setați un parametru sau parametri de interogare, dacă există, utilizând metoda setParameter a unei interogări adecvate.
  • 4. Dacă este necesar, setați numărul maxim de instanțe de recuperat și/sau specificați poziția primei instanțe de recuperat, utilizând metodele Setmaxresults și/sau Setfirstresult Query.
  • 5. Dacă este necesar, setați un indiciu specific furnizorului, utilizând metoda interogării setHint.
  • 6. Dacă este necesar, setați modul de spălare pentru executarea interogării cu metoda interogării setFlushMode, înlocuind modul de spălare al managerului entității.
  • 7. Executați interogarea folosind metoda unei interogări corespunzătoare: getSingleResult sau getResultList. Totuși, în cazul unei operații de actualizare sau ștergere, trebuie să utilizați metoda executeUpdate, care returnează numărul de instanțe de entitate actualizate sau șterse.

lista completă a metodelor de interfață EntityManager, precum și metodele de interfață API de interogare, pot fi găsite în documentul Enterprise JavaBeans 3.0 Specification: java Persistence API, care face parte din JSR-220.

acum că aveți o idee aproximativă despre cum puteți crea și apoi emite o interogare JPQL, vă recomandăm să vedeți câteva exemple practice. Următorul fragment de cod este preluat din metoda doGet a unui servlet care utilizează o interogare JPQL pentru a obține informații despre toți clienții stocați în tabelul relațional de bază asociat cu entitatea client specificată în interogare.

  ... @PersistenceUnit private EntityManagerFactory emf; public void doGet( ... EntityManager em = emf.createEntityManager(); PrintWriter out = response.getWriter(); List<Customer> arr_cust = (List<Customer>)em.createQuery("SELECT c FROM Customer c") .getResultList(); out.println("List of all customers: "+""); Iterator i = arr_cust.iterator(); Customer cust; while (i.hasNext()) { cust = (Customer) i.next(); out.println(cust.getCust_id()+""); out.println(cust.getCust_name()+""); out.println(cust.getEmail()+""); out.println(cust.getPhone()+""); out.println("----------------" + ""); } ... 

de interes special aici sunt metoda createQuery a instanței EntityManager și metoda getresultlist a instanței de interogare. CreateQuery EntityManager este folosit pentru a crea instanța de interogare a cărei metodă getResultList este apoi utilizat pentru a executa interogarea JPQL trecut la createQuery ca parametru. După cum ați putea ghici, metoda Getresultlist a interogării returnează rezultatul unei interogări ca o listă ale cărei elemente, în acest exemplu particular, sunt distribuite pentru a tasta client.

dacă aveți nevoie pentru a prelua un singur rezultat, interfața API interogare oferă metoda getSingleResult, așa cum se arată în exemplul următor. Rețineți, totuși, că utilizarea getSingleResult va provoca o excepție dacă obțineți mai multe rezultate înapoi.

de asemenea, acest exemplu ilustrează utilizarea metodei setParameter a interogării prin care puteți lega un argument la un parametru de interogare. Cu setParameter, puteți lega atât parametrii numiți, cât și cei poziționali. Aici, însă, legați un parametru numit.

  ... Integer cust_id =2; Customer cust = (Customer)em.createQuery("SELECT c FROM Customer c WHERE c.cust_id=:cust_id") .setParameter("cust_id", cust_id) .getSingleResult(); out.println("Customer with id "+cust.getCust_id()+" is: "+ cust.getCust_name()+""); ... 

este interesant de observat că utilizarea unei instrucțiuni JPQL selectate nu este singura modalitate de a merge atunci când vine vorba de recuperarea unei singure instanțe de entitate. Alternativ, puteți utiliza metoda de găsire a EntityManager, care vă permite să preluați o singură instanță de entitate bazată pe id-ul entității transmis ca parametru.

în unele situații, poate fi necesar să preluați doar câteva informații din instanța sau instanțele entității țintă, definind o interogare JPQL împotriva unui anumit câmp sau câmpuri de entitate. Așa ar arăta fragmentul de mai sus, dacă trebuie să recuperați numai valoarea câmpului cust_name al instanței entității client interogate aici:

  ... Integer cust_id =2; String cust_name = (String)em.createQuery("SELECT c.cust_name FROM Customer c WHERE c.cust_id=:cust_id") .setParameter("cust_id", cust_id) .getSingleResult(); out.println("Customer with id "+cust_id+" is: "+cust_name+""); ... 

în mod similar, pentru a obține întreaga listă de nume ale clienților, puteți utiliza următorul cod:

  ... List<String> arr_cust_name = (List<String>)em.createQuery("SELECT c.cust_name FROM Customer c") .getResultList(); out.println("List of all customers: "+"<br/>"); Iterator i = arr_cust_name.iterator(); String cust_name; while (i.hasNext()) { cust_name = (String) i.next(); out.println(cust_name+"<br/>"); } ... 

revenind la SQL, s-ar putea să vă amintiți că lista de selectare a unei interogări SQL poate fi compusă din mai multe câmpuri din tabel sau tabele specificate în clauza FROM. În JPQL, puteți utiliza, de asemenea, o listă de selectare compusă, selectând datele numai din câmpurile entității de interes. În acest caz, însă, trebuie să creați clasa la care veți arunca rezultatul interogării. În secțiunea următoare, veți vedea un exemplu de interogare de asociere JPQL a cărei listă de selectare este compusă din câmpurile derivate din mai multe entități.

definirea JPQL se alătură

ca SQL, JPQL vă permite să definiți se alăture interogări. Cu toate acestea, în SQL, definiți în mod normal o asociere care combină înregistrări din două sau mai multe tabele și/sau vizualizări, inclusiv numai câmpurile obligatorii din acele tabele și vizualizări din lista de selectare a interogării asociere. În schimb, lista de selectare a unei interogări de asociere JPQL include de obicei o singură entitate sau chiar un singur câmp de entitate. Motivul pentru aceasta constă în natura tehnologiei JPA. Odată ce obțineți o instanță de entitate, puteți naviga la instanțele sale conexe folosind metodele getter corespunzătoare. Această abordare face inutil pentru tine de a defini o interogare care va returna toate instanțele entității legate de interes dintr-o dată.

de exemplu, pentru a obține informații despre comenzi împreună cu elementele lor rând în SQL, va trebui să definiți o interogare de asociere atât în tabelele purchaseOrders, cât și în tabelele orderLineItems, specificând câmpurile din ambele tabele din lista de selectare a interogării. Cu toate acestea, atunci când utilizați JPQL, puteți defini o interogare numai peste entitatea PurchaseOrder și apoi navigați la instanțele OrderLineItem corespunzătoare utilizând metoda Getorderlineitems a PurchaseOrder, după cum este necesar. În acest exemplu, poate doriți să definiți o interogare JPQL peste entitățile PurchaseOrder și OrderLineItem numai dacă trebuie să filtrați instanțele PurchaseOrder preluate pe baza unei condiții sau condiții aplicate la OrderLineItem.

următorul fragment prezintă un exemplu de interogare jpql join în acțiune. Pentru a înțelege mai bine modul în care entitățile implicate sunt legate între ele, puteți reveni la figura 1 prezentată în secțiunea de aplicare a eșantionului mai devreme în articol.

  ... Double max = (Double) em.createQuery("SELECT MAX(p.price) FROM PurchaseOrder o JOIN o.orderLineItems l JOIN l.product p JOIN p.supplier s WHERE s.sup_name = 'Tortuga Trading'") .getSingleResult(); out.println("The highest price for an ordered product supplied by Tortuga Trading: "+ max + "<br/>"); ... 

în exemplul de mai sus, utilizați funcția max aggregate din clauza SELECT a interogării join pentru a determina produsul cu cel mai mare preț, dintre cele care au fost furnizate de Tortuga Trading și au fost comandate cel puțin o dată.

o situație mai frecventă este însă atunci când trebuie să calculați, să zicem, prețul total al produselor comandate, care au fost furnizate de un anumit furnizor. Aici poate fi utilă funcția SUM aggregate. În SQL, o astfel de interogare de asociere ar putea arăta astfel:

  SELECT SUM(p.price*l.quantity) FROM purchaseorders o JOIN orderlineitems l ON o.pono=l.pono JOIN products p ON l.prod_id=p.prod_id JOIN suppliers s ON p.sup_id=s.sup_id WHERE sup_name ='Tortuga Trading'; 

din păcate, funcția SUM utilizată în JPQL nu vă permite să treceți o expresie aritmetică ca argument. Ceea ce înseamnă acest lucru în practică este că nu veți putea trece p.Preț*l.cantitate ca argument pentru suma JPQL. Cu toate acestea, există modalități de a rezolva această problemă. În exemplul următor, definiți clasa LineItemSum al cărui constructor este apoi utilizat în lista de selectare a interogării, luând p.price și l.quantity ca parametri. Ceea ce face Constructorul LineItemSum este înmulțirea p.preț cu L.cantitate, economisind rezultatul la variabila sa de clasă rslt. Apoi, puteți itera prin lista LineItemSum preluată de interogare, însumând valorile variabilei Rslt a LineItemSum. Următorul fragment arată cum toate acestea pot fi implementate în cod:

  package jpqlexample.servlets; ... class LineItemSum { private Double price; private Integer quantity; private Double rslt; public LineItemSum (Double price, Integer quantity){ this.rslt = quantity*price; } public Double getRslt () { return this.rslt; } public void setRslt (Double rslt) { this.rslt = rslt; } } public class JpqlJoinsServlet extends HttpServlet { ... public void doGet( ... List<LineItemSum> arr = (List<LineItemSum>)em.createQuery ("SELECT NEW jpqlexample.servlets.LineItemSum(p.price, l.quantity) FROM PurchaseOrder o JOIN o.orderLineItems l JOIN l.product p JOIN p.supplier s WHERE s.sup_name = 'Tortuga Trading'") .getResultList(); Iterator i = arr.iterator(); LineItemSum lineItemSum; Double sum = 0.0; while (i.hasNext()) { lineItemSum = (LineItemSum) i.next(); sum = sum + lineItemSum.getRslt(); } out.println("The total cost of the ordered products supplied by Tortuga Trading: "+ sum + "<br/>"); } } 

printre altele, exemplul de mai sus ilustrează modul în care puteți utiliza o clasă Java personalizată, nu o clasă de entități, în lista de selectare a interogării JPQL care include câmpurile derivate din mai multe entități, aruncând rezultatul interogării la acea clasă. Cu toate acestea, în majoritatea cazurilor, va trebui să vă ocupați de interogări care primesc o instanță sau o listă de instanțe ale unei anumite entități.

instanțe de entitate preluate și contextul actual de persistență

rezultatele interogării din exemplele de articol până acum au fost pur și simplu tipărite. Cu toate acestea, în aplicațiile din lumea reală, poate fi necesar să efectuați câteva operații suplimentare asupra rezultatelor interogării. De exemplu, poate fi necesar să actualizați instanțele preluate și apoi să le persistați înapoi în baza de date. Acest lucru ridică întrebarea: sunt instanțele preluate de o interogare JPQL gata pentru a fi prelucrate în continuare de către aplicație sau sunt necesari câțiva pași suplimentari pentru a le pregăti pentru asta? În special, ar fi interesant să aflăm în ce stare, în ceea ce privește contextul actual de persistență, sunt instanțele entității recuperate.

dacă aveți ceva experiență cu persistența Java, ar trebui să știți ce este un context de persistență. Pentru a recapitula, un context de persistență este un set de instanțe de entitate gestionate de instanța EntityManager asociată cu acel context. În exemplele precedente, ați folosit metoda Createquery a EntityManager pentru a crea o instanță de interogare pentru executarea unei interogări JPQL. De fapt, API-ul EntityManager include mai mult de douăzeci de metode pentru a gestiona ciclul de viață al instanțelor entității, pentru a controla tranzacțiile și pentru a crea instanțe de interogare ale căror metode sunt apoi utilizate pentru a executa interogarea specificată și pentru a prelua rezultatul interogării.

în ceea ce privește un context de persistență, o instanță de entitate poate fi într-una din următoarele patru stări: nouă, gestionată, detașată sau eliminată. Folosind o metodă adecvată EntityManager lui, puteți schimba starea de o anumită instanță entitate după cum este necesar. Este interesant de observat, totuși, că numai instanțele în stare gestionată sunt sincronizate cu baza de date, atunci când se produce spălarea la baza de date. Pentru a fi mai precis, instanțele entității din starea eliminată sunt, de asemenea, sincronizate, ceea ce înseamnă că înregistrările bazei de date corespunzătoare acestor instanțe sunt eliminate din Baza de date.

în schimb, instanțele din starea nouă sau detașată nu vor fi sincronizate cu baza de date. De exemplu, dacă creați o nouă instanță PurchaseOrder și apoi invocați metoda Flush a EntityManager, o altă înregistrare nu va apărea în tabelul purchaseOrders la care este mapată entitatea PurchaseOrder. Acest lucru se datorează faptului că noua instanță Purchasecorder nu a fost atașată contextului persistenței. Iată cum ar putea arăta codul:

  ... em.getTransaction().begin(); Customer cust = (Customer) em.find(Customer.class, 1); PurchaseOrder ord = new PurchaseOrder(); ord.setOrder_date(new Date()); ord.setCustomer(cust); em.getTransaction().commit(); ... 

pentru a remedia problema, trebuie să invocați metoda persist a EntityManager pentru noua instanță PurchaseOrder înainte de a invoca culoarea, așa cum se arată în exemplul următor:

  ... em.getTransaction().begin(); Customer cust = (Customer) em.find(Customer.class, 1); PurchaseOrder ord = new PurchaseOrder(); ord.setOrder_date(new Date()); ord.setCustomer(cust); em.persist(ord); em.getTransaction().commit(); ... 

alternativ, cu condiția să setați opțiunea cascadă la PERSIST sau ALL atunci când definiți relația cu PurchaseOrder în entitatea client, puteți adăuga instanța PurchaseOrder nou creată la lista comenzilor asociate cu instanța client, înlocuind operațiunea persist cu următoarele:

  cust.getPurchaseOrders().add(ord); 

discuția de mai sus cu privire la stările instanței entității ne conduce la întrebarea interesantă dacă instanțele entității preluate de o interogare JPQL devin gestionate automat sau trebuie să aveți grijă să setați în mod explicit starea lor de gestionat. Conform specificației JPA, indiferent de modul în care preluați entitățile—indiferent dacă este metoda de găsire a EntityManager sau o interogare—acestea sunt atașate automat la contextul actual de persistență. Aceasta înseamnă că instanțele entității preluate de o interogare JPQL devin gestionate automat. Puteți, de exemplu, să modificați valoarea câmpului unei instanțe preluate și apoi să sincronizați acea modificare cu baza de date invocând metoda Flush a EntityManager sau comitând tranzacția curentă. Nu aveți nevoie să vă faceți griji cu privire la starea instanțelor asociate cu instanțele preluate, fie. Faptul este că prima dată când accesați o instanță asociată, aceasta devine gestionată automat. Iată un exemplu simplu care arată cum funcționează toate acestea în practică:

  ... em.getTransaction().begin(); PurchaseOrder ord = (PurchaseOrder)em.createQuery("SELECT o FROM PurchaseOrder o WHERE o.pono = 1") .getSingleResult(); List<OrderLineItem> items = ord.getOrderLineItems(); Integer qnt = items.get(0).getQuantity(); out.println("Quantity of the first item : "+ qnt +"<br/>"); items.get(0).setQuantity(qnt+1); qnt = items.get(0).getQuantity(); em.getTransaction().commit(); out.println("Quantity of the first item : "+ qnt +"<br/>"); ... 

rețineți că nu invocați metoda persist pentru instanța purchaseorder preluată și nici pentru instanța OrderLineItem aferentă care este modificată aici. În ciuda acestui fapt, modificările aduse primului element rând din comandă vor persista în baza de date la comiterea tranzacției. Acest lucru se întâmplă deoarece atât instanțele entității recuperate, cât și asociațiile lor sunt atașate automat la contextul actual de persistență. Așa cum am menționat mai devreme, primele devin gestionate atunci când sunt recuperate, iar cele din urmă sunt atașate contextului pe măsură ce le accesați.

în unele situații, este posibil să doriți ca asociațiile să fie atașate la context la executarea interogării, mai degrabă decât la primul acces. Acest lucru este în cazul în care un FETCH se alăture vine la îndemână. Spuneți, doriți să obțineți toate comenzile aparținând unui anumit client, la preluarea acelei instanțe a clientului. Această abordare garantează că aveți de-a face cu comenzile clienților disponibile în momentul executării interogării. Dacă, de exemplu, o comandă nouă este adăugată la un alt context și apoi sincronizată cu baza de date înainte de a accesa prima dată lista de comenzi asociată cu instanța de client preluată, nu veți vedea această modificare până când nu reîmprospătați starea instanței de client din Baza de date. În fragmentul următor, utilizați interogarea asociere care returnează instanța client al cărei cust_id este 1 și preia instanțele PurchaseOrder asociate cu instanța Client fiind preluate.

  ... Customer cust = (Customer)em.createQuery("SELECT DISTINCT c FROM Customer c LEFT JOIN FETCH c.purchaseOrders WHERE c.cust_id=1") .getSingleResult(); ... List<PurchaseOrder> orders = cust.getPurchaseOrders(); ... 

nefiind parte a rezultatului explicit al interogării, instanțele entității PurchaseOrder asociate cu instanța client preluată aici sunt, de asemenea, preluate și atașate la contextul de persistență curent la executarea interogării.

utilizarea interogărilor SQL Native

este interesant de observat că nu vă limitați la JPQL atunci când definiți interogări care urmează să fie apoi executate cu API-ul de interogare. S-ar putea să fiți surprins să aflați că API-ul EntityManager oferă metode pentru crearea instanțelor de interogare pentru executarea instrucțiunilor SQL native. Cel mai important lucru de înțeles despre interogările SQL native create cu metodele EntityManager este că acestea, cum ar fi interogările JPQL, returnează instanțele entității, mai degrabă decât înregistrările tabelelor bazei de date. Iată un exemplu simplu de interogare dinamică SQL nativă:

  ... List<Customer> customers = (List<Customer>)em.createNativeQuery ("SELECT * FROM customers", jpqlexample.entities.Customer.class) .getResultList(); Iterator i = customers.iterator(); Customer cust; out.println("Customers: " + "<br/>"); while (i.hasNext()) { cust = (Customer) i.next(); out.println(cust.getCust_name() +"<br/>"); } ... 

JPQL este încă în evoluție, și nu are multe dintre aceste caracteristici importante disponibile în SQL. În definirea JPQL se alătură secțiunea anterioară, ați văzut un exemplu de incompletitudine JPQL lui: ai avut de a face o mulțime de muncă pe cont propriu, deoarece JPQL suma agregat funcție nu poate lua o expresie aritmetică ca parametru. În schimb, funcția SUM SQL nu are o astfel de limitare. Deci, acesta este un bun exemplu în care înlocuirea JPQL cu SQL nativ ar putea fi eficientă. Următorul cod ilustrează modul în care s-ar putea simplifica lucrurile în acest exemplu particular prin alegerea SQL nativ peste JPQL:

  ... String sup_name ="Tortuga Trading"; BigDecimal sum = (List)em.createNativeQuery("SELECT SUM(p.price*l.quantity) FROM orders o JOIN orderlineitems l ON o.pono=l.pono JOIN products p ON l.prod_id=p.prod_id JOIN suppliers s ON p.sup_id=s.sup_id WHERE sup_name =?1") .setParameter(1, sup_name) .getSingleResult(); out.println("The total cost of the ordered products supplied by Tortuga Trading: " + sum +"<br/>"); ... 

printre altele, exemplul de mai sus ilustrează faptul că puteți lega argumentele la parametrii de interogare nativi. În special, puteți lega argumentele la parametrii poziționali în același mod ca și cum ați avea de-a face cu o interogare JPQL.

principalul dezavantaj al interogărilor native este complexitatea legării rezultatelor. În exemplu, interogarea produce un singur rezultat al unui tip simplu, evitând astfel această problemă. În practică, însă, de multe ori trebuie să vă ocupați de un set de rezultate de tip complex. În acest caz, va trebui să declarați o entitate la care puteți mapa interogarea nativă sau să definiți un set complex de rezultate mapat la mai multe entități sau la un amestec de entități și rezultate scalare.

utilizarea procedurilor stocate

un alt dezavantaj al interogărilor native este că codul Java devine direct dependent de structura bazei de date subiacente. Dacă modificați acea structură subiacentă, va trebui să ajustați interogările native în cauză în servleturile dvs. și / sau în alte componente ale aplicației, trebuind să recompilați și să redistribuiți acele componente după aceea. Pentru a rezolva această problemă, în timp ce utilizați încă interogări native, puteți profita de procedurile stocate, mutând interogări SQL complexe în programe stocate și executate în baza de date și apoi apelând acele programe stocate în loc să efectuați apeluri directe către tabelele subiacente. Ceea ce înseamnă acest lucru în practică este că procedurile stocate vă pot salva problemele de a trata tabelele subiacente direct din interogările care sunt codificate în codul Java. Beneficiul acestei abordări este că, în majoritatea cazurilor, nu va trebui să modificați codul Java pentru a urmări modificările din structura bazei de date subiacente. În schimb, numai procedurile stocate vor avea nevoie de fixare.

revenind la exemplul discutat în secțiunea precedentă, puteți muta interogarea complex join utilizată acolo într-o funcție stocată, creată după cum urmează:

  CREATE OR REPLACE FUNCTION sum_total(supplier VARCHAR2) RETURN NUMBER AS sup_sum NUMBER; BEGIN SELECT SUM(p.price*l.quantity) INTO sup_sum FROM orders o JOIN orderlineitems l ON o.pono=l.pono JOIN products p ON l.prod_id=p.prod_id JOIN suppliers s ON p.sup_id=s.sup_id WHERE sup_name = supplier; RETURN sup_sum; END; / 

acest lucru simplifică interogarea nativă utilizată în codul Java și elimină dependența din tabelele de bază:

  ... String sup_name ="Tortuga Trading"; BigDecimal sum = (BigDecimal)em.createNativeQuery("SELECT sum_total(?1) FROM DUAL") .setParameter(1, sup_name) .getSingleResult(); out.println("The total cost of the ordered products supplied by Tortuga Trading: " + sum +"<br/>"); ... 

concluzie

după cum ați învățat în acest articol, JPQL este un instrument puternic atunci când vine vorba de accesarea datelor relaționale din aplicațiile Java care utilizează persistența Java. Cu JPQL, spre deosebire de SQL/JDBC, definiți interogări peste entitățile JPA mapate la tabelele bazei de date subiacente, mai degrabă decât interogarea directă a acestor tabele, tratând astfel un strat de abstractizare care ascunde detaliile bazei de date din stratul logicii de afaceri. De asemenea, ați aflat că JPQL nu este singura opțiune atunci când vine vorba de crearea de interogări asupra entităților JPA—în unele situații, utilizarea interogărilor SQL native este mai convenabilă.