Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
laboratoare:laborator02 [2015/10/21 21:07] Andrei Roșu-Cojocaru |
laboratoare:laborator02 [2015/11/04 12:15] (current) Andrei Roșu-Cojocaru |
||
|---|---|---|---|
| Line 592: | Line 592: | ||
| * câmp sau proprietate de tip relație, putând avea o singură valoare; | * câmp sau proprietate de tip relație, putând avea o singură valoare; | ||
| * câmp sau proprietate de tip relație, putând avea o colecție de valori. | * câmp sau proprietate de tip relație, putând avea o colecție de valori. | ||
| - | |||
| O expresie de cale permite unei interogări JPQL să navigheze de-a lungul unor entități între care există o relație. Posibilitatea navigării într-un anumit punct este dată de multiplicitatea obiectului curent: | O expresie de cale permite unei interogări JPQL să navigheze de-a lungul unor entități între care există o relație. Posibilitatea navigării într-un anumit punct este dată de multiplicitatea obiectului curent: | ||
| Line 676: | Line 675: | ||
| Limbajul JPQL definește o serie de funcții care operează pe expresii de tipul șiruri de caractere, valori numerice sau de tip dată și timp, acestea putând fi utilizate în cadrul clauzelor ''SELECT'', ''WHERE'' și ''HAVING''. | Limbajul JPQL definește o serie de funcții care operează pe expresii de tipul șiruri de caractere, valori numerice sau de tip dată și timp, acestea putând fi utilizate în cadrul clauzelor ''SELECT'', ''WHERE'' și ''HAVING''. | ||
| + | |||
| + | **Funcții pentru șiruri de caractere** | ||
| + | |||
| + | <note>În cadrul unui șir de caractere, indexarea se face începând cu valoarea 1.</note> | ||
| + | |||
| + | ^ **SEMNĂTURĂ METODĂ** ^ **TIP ÎNTORS** ^ | ||
| + | | ''CONCAT(String, String)'' | ''String'' | | ||
| + | | ''LENGTH(String)'' | ''int'' | | ||
| + | | ''LOCATE(String, String, [, start])'' | ''int'' | | ||
| + | | ''SUBSTRING(String, start, length)'' | ''String'' | | ||
| + | | ''TRIM[([LEADING|TRAILING|BOTH] char) FROM] (String)'' | ''String'' | | ||
| + | | ''LOWER(String)'' | ''String'' | | ||
| + | | ''UPPER(String)'' | ''String'' | | ||
| + | |||
| + | Funcția ''CONCAT'' unește două șiruri de caractere într-un singur șir de caractere. | ||
| + | |||
| + | Funcția ''LENGTH'' furnizează lungimea unui șir de caractere sub forma unui număr întreg. | ||
| + | |||
| + | Funcția ''LOCATE'' furnizează poziția la care un subșir se găsește în cadrul unui șir. Opțional, căutarea poate fi realizată începând cu o anumită poziție (implicit, căutarea se face începând cu poziția 1). Dacă subșirul nu se găsește în cadrul șirului, rezultatul întors va fi 0. | ||
| + | |||
| + | Funcția ''SUBSTRING'' calculează un subșir al unui șir, pornind de la o anumită poziție și având o anumită lungime. | ||
| + | |||
| + | Funcția ''TRIM'' elimină caracterul specificat (opțional) de la începutul și / sau de la sfârșitul unui șir de caractere. În cazul în care nu se precizează nici un parametru opțional, sunt eliminate spațiile din cadrul șirului de caractere. | ||
| + | * ''LEADING'' - sunt eliminate numai caracterele de la începutul șirului; | ||
| + | * ''TRAILING'' - sunt eliminate numai caracterele de la sfârșitul șirului; | ||
| + | * ''BOTH'' - sunt eliminate atât caracterele de la încputul șirului cât și caracterele de la sfârșitul șirului. | ||
| + | |||
| + | Funcțiile ''LOWER'' și ''UPPER'' convertesc toate caracterele unui șir de caractere la minuscule, respectiv la majuscule. | ||
| + | |||
| + | **Funcții pentru valori numerice** | ||
| + | |||
| + | ^ **SEMNĂTURĂ METODĂ** ^ **TIP ÎNTORS** ^ | ||
| + | | ''ABS(number)'' | ''int'', ''float'' sau ''double'' | | ||
| + | | ''MOD(int, int)'' | ''int'' | | ||
| + | | ''SQRT(double)'' | ''double'' | | ||
| + | | ''SIZE(Collection)'' | int | | ||
| + | |||
| + | Funcția ''ABS'' primește ca parametru o expresie numeric și furnizează modulul valorii respective, având același tip de date ca și parametrul. | ||
| + | |||
| + | Funcția ''MOD'' returnează restul împărțirii numerelor primite ca parametri. | ||
| + | |||
| + | Funcția ''SQRT'' calculează rădăcina pătrată a valorii transmisă ca parametru. | ||
| + | |||
| + | Funcția ''SIZE'' furnizează numărul de elemente din colecția transmisă ca parametru. | ||
| + | |||
| + | **Funcții pentru expresii de tip dată / timp** | ||
| + | |||
| + | Funcțiile pentru expresiile de tip dată / timp furnizează momentul curent, în diferite formate, în funcție de necesități. | ||
| + | |||
| + | ^ **SEMNĂTURĂ METODĂ** ^ **TIP ÎNTORS** ^ | ||
| + | | ''CURRENT_DATE'' | ''java.sql.Date'' | | ||
| + | | ''CURRENT_TIME'' | ''java.sql.Time'' | | ||
| + | | ''CURRENT_TIMESTAMP'' | ''java.sqlTimestamp'' | | ||
| + | |||
| + | Expresiile de tip ''CASE'' furnizează un set de condiții alternative pentru o expresie, indiferent de tipul ei precum și o acțiune implicită care va fi realizată dacă nici una dintre condițiile anterioare nu a fost întrunită. Pot fi comparate expresii având orice tip de date. | ||
| + | |||
| + | O astfel de instrucțiune începe prin cuvântul-cheie ''CASE'' urmat de valoarea expresiei care se dorește a fi evaluată și se termină prin ''END''. Valorile posibile sunt specificate prin ''WHEN'' iar acțiunile corespunzătoare sunt precizate prin ''THEN''. Prin cuvântul-cheie ''ELSE'' se indică acțiunea care va fi realizată dacă nici una dintre condițiile anterioare nu a fost întrunită. | ||
| + | |||
| + | <code jpql> | ||
| + | CASE expression | ||
| + | WHEN value1 THEN action1 | ||
| + | [WHEN value2 THEN action2] | ||
| + | ... | ||
| + | [WHEN valuen THEN actionn] | ||
| + | [ELSE action] | ||
| + | END | ||
| + | </code> | ||
| + | |||
| + | <note tip>Tipul unei entități persistente poate fi obținut prin funcția ''TYPE''.</note> | ||
| + | |||
| + | În situația în care o referință către o entitate nu este identificată în sursa de date, valoarea acesteia este ''NULL''. | ||
| + | |||
| + | Evaluarea expresiilor care conțin valori de tip ''NULL'' este aceeași ca în limbajul SQL standard. | ||
| + | * o comparație sau o operație aritmetică care are o valoare necunoscută este evaluată la ''NULL''; | ||
| + | * două valori ''NULL'' nu sunt egale, compararea acestora rezultând într-o valoare necunoscută; | ||
| + | * testul ''IS NULL'' convertește o entitate persistentă vidă la ''TRUE'' la fel cum testul ''IS NOT NULL'' convertește o entitate persistentă nevidă la ''FALSE''; | ||
| + | * operatorii logici folosesc 3 valori pentru aceste tipuri de date: adevărat, fals și necunoscut. | ||
| + | |||
| + | <html> | ||
| + | <center> | ||
| + | </html> | ||
| + | |||
| + | ^ **AND** ^ **T**rue ^ **F**alse ^ **U**nknown ^ | ||
| + | | **T**rue | True | False | Unknown | | ||
| + | | **F**alse | False | False | False | | ||
| + | | **U**nknown | Unknown | False | Unknown | | ||
| + | |||
| + | ^ **OR** ^ **T**rue ^ **F**alse ^ **U**nknown ^ | ||
| + | | **T**rue | True| True | True | | ||
| + | | **F**alse | True | False | Unknown | | ||
| + | | **U**nknown | True | Unknown | Unknown | | ||
| + | |||
| + | ^ **NOT** ^ **REZULTAT** ^ | ||
| + | | **T**rue | False | | ||
| + | | **F**alse | True | | ||
| + | | **U**nknown | Unknown | | ||
| + | |||
| + | <html> | ||
| + | </center> | ||
| + | </html> | ||
| + | |||
| + | În limbajul JPQL, numai valorile de același tip pot fi comparate, cu o singură excepție (valorile numerice exacte și aproximative, situație în care are loc conversia de tip). | ||
| + | |||
| + | Operațiile de comparare sunt realizate asupra valorilor la nivel de obiecte Java și nu asupra modului în care acestea sunt reprezentate în sursa de date. Din acest motiv, în clasele de tip entitate trebuie să se utilizeze tipuri de date derivate din ''Object'' care pot avea valoarea ''NULL'' și nu tipuri de date primitive care nu au această proprietate. | ||
| + | |||
| + | <html> | ||
| + | <center> | ||
| + | </html> | ||
| + | |||
| + | ^ **TEST CONDIȚIONAL** ^ **T**rue ^ **F**alse ^ **U**nknown ^ | ||
| + | | ''IS TRUE'' | True | False | False | | ||
| + | | ''IS FALSE'' | False | True | False | | ||
| + | | expresia este necunoscută | False | False | False | | ||
| + | |||
| + | <html> | ||
| + | </center> | ||
| + | </html> | ||
| **4**. **GROUP BY**: grupează valorile furnizate conform unor criterii bazate pe un set de proprietăți; | **4**. **GROUP BY**: grupează valorile furnizate conform unor criterii bazate pe un set de proprietăți; | ||
| Line 702: | Line 818: | ||
| === Criteria API === | === Criteria API === | ||
| + | |||
| + | Criteria API este utilizat pentru a defini interogări pentru entități persistente și pentru relațiile dintre ele în cadrul unor obiecte, folosind limbajul de programare Java. Astfel, interogările vor fi portabile (raportat la sursa de date utilizată) și nu există posibilitatea de a apărea probleme legate de conversiile între tipurile de date. | ||
| + | |||
| + | Și Criteria API funcționează pe baza unor scheme abstracte ale entităților persistente, pe relațiile dintre acestea și pe obiecte imbricate, oferind funcționalități pentru interogarea, modificarea și ștergerea valorilor din sursa de date prin invocarea operațiilor corespunzătoare din cadrul JPA. Este definită și o altă interfață de programare, Metamodel API, prin intermediul căruia entitățile persistente sunt modelate pentru a putea fi utilizate adecvat. | ||
| + | |||
| + | Etapele necesare pentru a realiza o interogare folosind Criteria API sunt: | ||
| + | - construirea unui obiect [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/CriteriaBuilder.html|javax.persistence.criteria.CriteriaBuilder]] prin invocarea metodei [[http://docs.oracle.com/javaee/7/api/javax/persistence/EntityManager.html#getCriteriaBuilder--|getCriteriaBuilder()]] a clasei ''EntityManager'' <code java> | ||
| + | CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); | ||
| + | </code> | ||
| + | - definirea unui obiect interogare, de tip [[https://docs.oracle.com/javaee/7/api/javax/persistence/criteria/CriteriaQuery.html|javax.persistence.criteria.CriteriaQuery]], prin apelul metodei [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/CriteriaBuilder.html#createQuery-java.lang.Class-|createQuery()]] din interfața ''CriteriaBuilder''; atributele acestui obiect interogare, parametrizat la tipul de date al rezultatului furnizat, vor fi modificate prin detaliile interogării: <code java> | ||
| + | CriteriaQuery<Book> criteriaQuery = criteriaBuilder.createQuery(Book.class); | ||
| + | </code> | ||
| + | - precizarea entității persistente rădăcină (punctul inițial al interogării) prin apelarea metodei [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/AbstractQuery.html#from-java.lang.Class-|from()]] a obiectului de tip ''CriteriaQuery''; se obține astfel un obiect de tip [[https://docs.oracle.com/javaee/7/api/javax/persistence/criteria/Root.html|javax.persistence.criteria.Root]], parametrizat și acesta la tipul de entitate persistenă respectivă; se indică astfel clauza FROM a interogării: <code java> | ||
| + | Root<Boot> book = criteriaQuery.from(Book.class); | ||
| + | </code> | ||
| + | - indicarea tipului de rezultat care va fi furnizat în urma execuției interogării prin apelul metodei [[https://docs.oracle.com/javaee/7/api/javax/persistence/criteria/CriteriaQuery.html#select-javax.persistence.criteria.Selection-|select()]] pe obiectul ''CriteriaQuery''; prin acest apel se stabilește clauza SELECT a interogării: <code java> | ||
| + | criteriaQuery.select(); | ||
| + | </code> | ||
| + | - pregătirea interogării pentru a fi executată, prin instanțierea unui obiect de tip [[http://docs.oracle.com/javaee/7/api/javax/persistence/TypedQuery.html|TypedQuery]], prin care se indică tipul de date al rezultatului furnizat; un astfel de obiect poate fi rulat la nivelul sursei de date; el se obține prin apelul metodei ''createQuery()'' a obiectului de tip ''EntityManager'' căruia i se furnizează ca parametru obiectul ''CriteriaQuery'' creat anterior; astfel, modificările aduse la detaliile interogării sunt stocate astfel încât interogarea să fie pregătită spre a putea fi executată: <code java> | ||
| + | TypedQuery<Book> typedQuery = entityManager.createQuery(criteriaQuery); | ||
| + | </code> | ||
| + | - execuția interogării se face apelând metoda [[http://docs.oracle.com/javaee/7/api/javax/persistence/TypedQuery.html#getResultList--|getResultList()]] din clasa ''TypedQuery'', care furnizează lista de rezultate, garantând faptul că acestea au exact tipul de date așteptat: <code java> | ||
| + | List<Book> allBooks = typedQuery.getResultList(); | ||
| + | </code> | ||
| + | |||
| + | == Utilizarea Metamodel API == | ||
| + | |||
| + | Prin intermediul interfeței de programare Metamodel API, se definește un metamodel pentru entitățile gestionate în cadrul unei unități de persistență. Astfel, pentru fiecare entitate, este necesar să se definească și o clasă metamodel, având aceeași denumire, la care este sufixat caracterul ''_''. | ||
| + | |||
| + | <file java Book.java> | ||
| + | package ro.pub.cs.aipi.lab02.entities; | ||
| + | |||
| + | import java.util.Set; | ||
| + | |||
| + | import javax.persistence.Column; | ||
| + | import javax.persistence.Entity; | ||
| + | import javax.persistence.GeneratedValue; | ||
| + | import javax.persistence.GenerationType; | ||
| + | import javax.persistence.Id; | ||
| + | import javax.persistence.JoinColumn; | ||
| + | import javax.persistence.JoinTable; | ||
| + | import javax.persistence.ManyToMany; | ||
| + | import javax.persistence.OneToOne; | ||
| + | import javax.persistence.Table; | ||
| + | |||
| + | @Entity | ||
| + | @Table(name = "bookstore.book") | ||
| + | public class Book extends PersistentEntity { | ||
| + | |||
| + | @Id | ||
| + | @GeneratedValue(strategy = GenerationType.AUTO) | ||
| + | @Column(name = "id") | ||
| + | protected Long id; | ||
| + | @Column(name = "title") | ||
| + | protected String title; | ||
| + | @Column(name = "subtitle") | ||
| + | protected String subtitle; | ||
| + | @ManyToMany(targetEntity = Writer.class) | ||
| + | @JoinTable(name="bookstore.author", joinColumns=@JoinColumn(name="book_id"), inverseJoinColumns=@JoinColumn(name="writer_id")) | ||
| + | protected Set<Writer> writers; | ||
| + | @Column(name = "description") | ||
| + | protected String description; | ||
| + | @Column(name = "edition") | ||
| + | protected Long edition; | ||
| + | @Column(name = "printing_year") | ||
| + | protected Long printingYear; | ||
| + | @OneToOne | ||
| + | @JoinColumn(name = "collection_id", unique = false, nullable = false, updatable = true) | ||
| + | protected Collection collection; | ||
| + | @ManyToMany(targetEntity = Category.class) | ||
| + | @JoinTable(name="bookstore.category_content", joinColumns=@JoinColumn(name="book_id"), inverseJoinColumns=@JoinColumn(name="category_id")) | ||
| + | protected Set<Category> categories; | ||
| + | |||
| + | // ... | ||
| + | } | ||
| + | </file> | ||
| + | |||
| + | Interogările construite folosind Criteria API folosesc clasa metamodel și atributele sale pentru a referi clasele entitate gestionate împreună cu câmpurile și atributele lor, precum și relațiile dintre acestea. | ||
| + | |||
| + | Clasele metamodel care corespund entităților persistente au tipul [[https://docs.oracle.com/javaee/7/api/javax/persistence/metamodel/EntityType.html|javax.persistence.metamodel.EntityType<T>]]. | ||
| + | |||
| + | De regulă, procesoarele de adnotări generează clasele metamodel fie în momentul compilării, fie în momentul rulării. În cazul utilizării Criteria API, există două abordări: | ||
| + | - generarea statică a claselor metamodel prin utilizarea procesorului de adnotări al furnizorului JPA, [[http://docs.oracle.com/javaee/7/api/javax/persistence/metamodel/Metamodel.html|javax.persistence.metamodel.Metamodel]] <file java Book_.java> | ||
| + | package ro.pub.cs.aipi.lab02.entities; | ||
| + | |||
| + | import javax.persistence.metamodel.SetAttribute; | ||
| + | import javax.persistence.metamodel.SingularAttribute; | ||
| + | import javax.persistence.metamodel.StaticMetamodel; | ||
| + | |||
| + | @StaticMetamodel(Book.class) | ||
| + | public class Book_ { | ||
| + | public static volatile SingularAttribute<Book, Long> id; | ||
| + | public static volatile SingularAttribute<Book, String> title; | ||
| + | public static volatile SingularAttribute<Book, String> subtitle; | ||
| + | public static volatile SetAttribute<Book, Writer> writers; | ||
| + | public static volatile SingularAttribute<Book, Long> edition; | ||
| + | public static volatile SingularAttribute<Book, Long> printingYear; | ||
| + | public static volatile SingularAttribute<Book, Collection> collection; | ||
| + | public static volatile SetAttribute<Book, Category> categories; | ||
| + | } | ||
| + | </file> | ||
| + | - obținerea clasei metamodel prin: | ||
| + | - apelarea metodei [[https://docs.oracle.com/javaee/7/api/javax/persistence/criteria/Root.html#getModel--|getModel()]] a obiectului rădăcină al interogării; <code java> | ||
| + | CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); | ||
| + | CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Book.class); | ||
| + | Root<Book> book = criteriaQuery.from(Book.class); | ||
| + | EntityType<Book> Book_ = book.getMode(); | ||
| + | </code> | ||
| + | - obținerea unei instanțe a clasei ''Metamodel'' și apelarea metodei [[http://docs.oracle.com/javaee/7/api/javax/persistence/metamodel/Metamodel.html#entity-java.lang.Class-|entity()]] a acestui obiect <code java> | ||
| + | Metamodel metamodel = entityManager.getMetamodel(); | ||
| + | EntityType<Book> Book_ = metamodel.entity(Book.class); | ||
| + | </code> | ||
| + | |||
| + | <note tip>În practică, se obișnuiește să se definească o clasă metamodel statică, care va asigura faptul că nu se vor produce erori la conversiile de tip de date. Obținerea claselor metamodel dinamic, prin oricare din cele două mecanisme (apelul metodei ''getModel()'' a clasei ''Root'', respectiv invocarea metodei ''entity()'' pe clasa ''Metamodel'') nu asigură faptul că nu se vor produce erori la conversiile de tip și nici nu oferă aplicației acces la câmpurile și proprietățile persistente din clasa metamodel.</note> | ||
| + | |||
| + | == Utilizarea Interogărilor == | ||
| + | |||
| + | O interogare folosind Criteria API implică definirea clauzelor obligatorii SELECT și FROM precum și a celor opționale (WHERE, GROUP BY, HAVING, ORDER BY) prin intermediul unor obiecte Java, astfel încât să se evite generarea de excepții datorate conversiilor de tipuri în momentul în care sunt obținute rezultatele. | ||
| + | |||
| + | Interfața [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/CriteriaBuilder.html|javax.persistence.criteria.CriteriaBuilder]] este utilizată pentru a furniza interogări, selecții, expresii, predicate și criterii de sortare. | ||
| + | |||
| + | Un obiect ''CriteriaBuilder'' se obține prin invocarea metodei ''getCriteriaBuilder()'' pe un obiect de tipul ''EntityManager'': <code java> | ||
| + | CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); | ||
| + | </code> | ||
| + | |||
| + | Interogările sunt construite prin intermediul unui obiect de tipul [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/CriteriaQuery.html|CriteriaQuery]], acesta având posibilitatea de a accesa una sau mai multe entități la un moment dat. De regulă, se utilizează una dintre variantele metodei supraîncărcate ''createQuery()'' a clasei ''CriteriaBuilder'', însă pentru a se evita posibilitatea de generare a unor excepții legate de conversiile de tipuri, se recomandă să se utilizeze metoda care primește ca parametru tipul de date al entității care va fi furnizată ca rezultat [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/CriteriaBuilder.html#createQuery-java.lang.Class-|createQuery()]]. <code java> | ||
| + | CriteriaQuery<Book> criteriaQuery = criteriaBuilder.createQuery(Book.class); | ||
| + | </code> | ||
| + | |||
| + | Pentru un obiect de tip ''CriteriaQuery'' este necesar să se definească o entitate rădăcină, care reprezintă punctul inițial în traversarea ierarhiei de clase pentru obținerea rezultatului interogării. Din acest motiv, un astfel de obiect mai poartă și denumirea de rădăcină a interogării, desemnând funcționalitatea clauzei FROM. | ||
| + | |||
| + | O instanță de tipul [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/Root.html|Root<T>]] se obține apelând metoda [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/AbstractQuery.html#from-java.lang.Class-|from()]] a obiectului de tip ''CriteriaQuery'', care poate primi ca parametru fie tipul de date al clasei entitate fie o instanță de tipul ''EntityType<T>'' | ||
| + | |||
| + | <code java> | ||
| + | Root<Book> book = criteriaQuery.from(Book.class); | ||
| + | </code> | ||
| + | |||
| + | <code java> | ||
| + | Root<Book> book = criteriaQuery.from(Book_); | ||
| + | </code> | ||
| + | |||
| + | Interogările pot avea una sau mai multe rădăcini, situație întâlnită în cazul operațiilor de asociere dintre entități. | ||
| + | |||
| + | În situația în care rezultatele aparțin mai multor entități, interogarea trebuie să definească o asociere către obiectul referit, apelând una dintre metodele ''join()'' descrise de clasa [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/From.html|javax.persistence.criteria.From]]. Acestea folosesc o clasă metamodel de tipul ''EntityType<T>'' pentru a indica câmpul sau proprietatea persistente din entitatea cu care se face legătura și furnizează un obiect de tipul [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/Join.html|javax.persistence.criteria.Join(X,Y)]], unde X reprezintă entitatea copil iar Y reprezintă entitatea părinte. | ||
| + | |||
| + | <code java> | ||
| + | Root<Book> book = criteriaQuery.from(Book.class); | ||
| + | Join<Book, Category> joinBookCategory = book.join(Book_.categories); | ||
| + | </code> | ||
| + | |||
| + | Metoda ''join()'' poate fi invocată în cascadă, până se ajunge la tipul de asociere dorit. | ||
| + | |||
| + | Obiectele de tip [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/Path.html|javax.persistence.criteria.Path]], folosite în clauzele SELECT și WHERE ale unei interogări, pot fi de tipul rădăcină, asociere sau de alt tip. Metodele [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/Path.html#get-java.lang.String-|get()]] ale acestei clase oferă acces la câmpurile și proprietățile unei entități. Acesta primește ca parametru atributul corespunzător din clasa metamodel, care poate conține o singură valoare (specificat cu adnotarea ''@SingularAttribute'') sau o colecție de valori (specificate prin adnotările ''@CollectionAttribute'', ''@SetAttribute'', ''@ListAttribute'', ''@MapAttribute''). | ||
| + | |||
| + | <code java> | ||
| + | CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); | ||
| + | CriteriaQuery<Book> criteriaQuery = criteriaBuilder.createQuery(Book.class); | ||
| + | Root<Book> book = criteriaQuery.from(Book.class); | ||
| + | criteriaQuery.select(book.get(Book_.title)); | ||
| + | </code> | ||
| + | |||
| + | Constrângerile unei interogări, incluse în clauzele WHERE sau HAVING, pot fi precizate prin intermediul metodei [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/CriteriaQuery.html#where-javax.persistence.criteria.Expression-|where()]] din clasa ''CriteriaQuery''. Aceasta evaluează instanțele interfeței [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/Expression.html|Expression]] pentru a filtra rezultatele interogării în funcție de condițiile pe care acestea le conțin. Condițiile vor fi precizate prin intermediul metodelor specifice din interfațele ''Expression'' respectiv ''CriteriaBuilder''. Un obiect de tip ''Expression'' poate fi inclus și în clauza SELECT. | ||
| + | |||
| + | Interfața ''Expression'' definește metode prin care rezultatele unei interogări pot fi filtrate. | ||
| + | |||
| + | ^ **METODA** ^ **DESCRIERE** ^ | ||
| + | | ''isNull()'' | verifică dacă o expresie are valoarea null | | ||
| + | | ''isNotNull()'' | verifică dacă o expresie nu are valoarea null | | ||
| + | | ''in()'' | verifică dacă valoarea unei expresii se găsește într-o anumită listă | | ||
| + | |||
| + | <code java> | ||
| + | criteriaQuery.where(book.get(Book_.subtitle).isNotNull()); | ||
| + | </code> | ||
| + | |||
| + | Interfața ''CriteriaBuilder'' definește metode prin care rezultatele unei interogări pot fi filtrate. | ||
| + | |||
| + | ^ **METODA** ^ **DESCRIERE** ^ | ||
| + | | ''equal'' | verifică dacă două expresii sunt egale | | ||
| + | | ''notEqual()'' | verifică dacă două expresii nu sunt egale | | ||
| + | | ''gt()'' | verifică dacă prima expresie numerică este strict mai mare decât a doua expresie numerică | | ||
| + | | ''ge()'' | verifică dacă prima expresie numerică este mai mare sau egală cu a doua expresie numerică | | ||
| + | | ''lt()'' | verifică dacă prima expresie numerică este strict mai mică decât a doua expresie numerică | | ||
| + | | ''le()'' | verifică dacă prima expresie numerică este mai mică sau egală cu a doua expresie numerică | | ||
| + | | ''between()'' | verifică o expresie se găsește între alte două expresii | | ||
| + | | ''like()'' | verifică dacă o expresie verifică un anumit șablon | | ||
| + | |||
| + | <code java> | ||
| + | criteriaQuery.where(cb.equal(book.get(Book_.title), "Thinking in Java")); | ||
| + | </code> | ||
| + | |||
| + | În situația în care se folosesc condiții compuse, legate între ele prin operatori logici, pot fi folosite metodele ''and()'', ''or()'' și ''not()'', disponibile în interfața ''CriteriaBuilder''. | ||
| + | |||
| + | <code java> | ||
| + | criteriaQuery.where(cb.equal(book.get(Book_.title), "Thinking in Java").and(cb.gt(book.get(Book_.printingYear), 2000))); | ||
| + | </code> | ||
| + | |||
| + | Pentru interogările care furnizează mai multe rezultate, se poate dovedi util ca acestea să fie organizate. În acest sens, interfața ''CriteriaQuery'' definește metodele: | ||
| + | * [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/CriteriaQuery.html#orderBy-java.util.List-|orderBy()]] ordonează rezultatele interogării în funcție de atributele unei entități; | ||
| + | * [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/CriteriaQuery.html#groupBy-java.util.List-|groupBy()]] grupează împreună rezultatele unei interogări în funcție de atributele unei entități, restricții suplimentare asupra acestor grupuri putând fi precizate prin intermediul metodei [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/CriteriaQuery.html#having-javax.persistence.criteria.Expression-|having()]]. | ||
| + | |||
| + | Metoda ''orderBy()'' primește ca parametru obiecte de tip [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/Order.html|javax.persistence.criteria.Order]] obținute prin apelul metodelor [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/CriteriaBuilder.html#asc-javax.persistence.criteria.Expression-|asc()]] respectiv [[http://docs.oracle.com/javaee/7/api/javax/persistence/criteria/CriteriaBuilder.html#desc-javax.persistence.criteria.Expression-|desc()]] din interfața ''CriteriaBuilder'', care indică criteriul de sortare (crescător, respectiv descrescător). | ||
| + | |||
| + | <code java> | ||
| + | CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); | ||
| + | CriteriaQuery<Book> criteriaQuery = criteriaBuilder.createQuery(Book.class); | ||
| + | Root<Book> book = criteriaQuery.from(Book.class); | ||
| + | criteriaQuery.select(book.get(Book_.title)); | ||
| + | criteriaQuery.orderBy(criteriaBuilder.desc(book.get(Book_.printingYear), book.get(Book_.edition))); | ||
| + | </code> | ||
| + | |||
| + | <note tip>În cazul în care se dorește precizarea mai multor criterii de ordonare, acestea vor fi transmise sub forma unei liste ca parametru al metodei ''orderBy()'', prioritatea fiind dată de ordinea de apariție în cadrul acesteia.</note> | ||
| + | |||
| + | Metoda ''groupBy()'' partiționează rezultatele interogării în mai multe grupuri. Aceasta poate fi utilizată împreună cu metoda ''having()'' pentru a filtra informațiile de la nivelul grupurilor, aceasta primind ca parametru o expresie condițională. | ||
| + | |||
| + | <code java> | ||
| + | CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); | ||
| + | CriteriaQuery<Book> criteriaQuery = criteriaBuilder.createQuery(Book.class); | ||
| + | Root<Book> book = criteriaQuery.from(Book.class); | ||
| + | criteriaQuery.select(book.get(Book_.title)); | ||
| + | criteriaQuery.groupBy(book.get(Book_.printingYear)); | ||
| + | criteriaQuery.having(book.get(Book_.title).like("%Thinking in Java%")); | ||
| + | </code> | ||
| + | |||
| + | O interogare este pregătită pentru execuție în momentul în care se apelează metoda [[http://docs.oracle.com/javaee/7/api/javax/persistence/EntityManager.html#createQuery-javax.persistence.criteria.CriteriaQuery-|createQuery()]] din clasa ''EntityManager'', aceasta furnizând un obiect de tipul [[http://docs.oracle.com/javaee/7/api/javax/persistence/TypedQuery.html|TypedQuery<T>]]. | ||
| + | |||
| + | Rularea propriu-zisă a interogării se face prin intermediul uneia dintre metodele definite în clasa ''TypedQuery<T>'': | ||
| + | * [[http://docs.oracle.com/javaee/7/api/javax/persistence/TypedQuery.html#getSingleResult--|getSingleResult()]], în situația în care este întors un singur rezultat; | ||
| + | * [[http://docs.oracle.com/javaee/7/api/javax/persistence/TypedQuery.html#getResultList--|getResultList()]], pentru cazul în care sunt furnizate mai multe rezultate. | ||
| + | |||
| + | În cadrul Criteria API sunt definite și interogări bazate pe șiruri de caractere, care precizează valorile atributelor unei entități prin intermediul unor valori hardcodate, în loc de a folosi obiectele din metamodel. O astfel de abordare furnizează o tipare slabă, comparativ cu soluția în care tiparea era tare. Similar, interogările pot fi statice sau dinamice și oferă aceleași funcționalități. | ||
| + | |||
| + | Avantajul utilizării interogărilor bazate pe șiruri de caractere constă în posibilitatea de construire a obiectelor interogare la momentul compilării, fără a fi necesar să se genereze în momentul rulării pe baza metamodelului. | ||
| + | |||
| + | Dezavantajul utilizării interogărilor bazate pe șiruri de caractere se referă la lipsa de siguranță în privința tipurilor de date ale rezultatelor furnizate, ceea ce poate conduce la excepții care nu pot fi prevăzute, cauzate de operațiile de conversie. | ||
| + | |||
| + | <code java> | ||
| + | criteriaQuery.where(cb.equal(book.get("title"), "Thinking in Java").and(cb.gt(book.get("printingYear"), 2000))); | ||
| + | </code> | ||
| ===== Configurarea mediilor integrate de dezvoltare ===== | ===== Configurarea mediilor integrate de dezvoltare ===== | ||
| Line 749: | Line 1103: | ||
| ==== Eclipse Mars (4.5) ==== | ==== Eclipse Mars (4.5) ==== | ||
| - | ==== Netbeans 8.0.2 ==== | + | În mediul integrat de dezvoltare Eclipse, activarea JPA se face din meniul contextual (accesibil prin click dreapta pe denumirea sa, în //Package Explorer//) al proiectului, în care pot fi configurate proprietățile acestuia. |
| + | |||
| + | În secțiunea //Project Facets// se bifează opțiunea //JPA//. Tot aici poate fi vizualizată și versiunea curentă a acestei interfețe de programare a aplicațiilor. | ||
| + | |||
| + | {{ :laboratoare:laborator02:eclipse01.png?nolink&700 }} | ||
| + | |||
| + | În secțiunea //JPA//, pot fi controlate următoarele proprietăți: | ||
| + | * furnizorul JPA (în cazul de față, Hibernate, acesta fiind configurat din fișierul ''persistence.xml'', dacă nu există o astfel de valoare în lista de opțiuni, lăsându-se valoarea implicită //Generic 2.1//) precum și versiunea curentă a interfeței de programare a aplicațiilor; | ||
| + | * biblioteca ce oferă funcționalitatea referitoare la accesul la date (se poate alege valoarea //Disable Library Configuration// în situația în care se folosește un sistem de tip Maven); | ||
| + | * conexiunea la baza de date (acesta poate fi de asemenea configurat în fișierul ''persistence.xml''); | ||
| + | * mecanismul prin care sunt gestionate clasele persistente (descoperire automată pe baza adnotărilor, respectiv precizarea lor în fișierul ''persistence.xml''); | ||
| + | * locația la care pot fi accesate clasele metamodel. | ||
| + | |||
| + | {{ :laboratoare:laborator02:eclipse02.png?nolink&700 }} | ||
| + | |||
| + | ==== NetBeans 8.0.2 ==== | ||
| + | |||
| + | În mediul integrat de dezvoltare NetBeans, nu este necesară activarea JPA, acest lucru realizându-se în momentul în care este detectat fișierul ''persistence.xml'' în directorul ''resources/META-INF'' din codul sursă. | ||
| + | |||
| + | {{ :laboratoare:laborator02:netbeans01.png?nolink }} | ||
| + | |||
| + | Acesta poate fi editat atât în mod vizual (//Design//) cât și în mod text (//Source//). | ||
| + | |||
| + | Pot fi configurate: | ||
| + | * denumirea unității de persistență; | ||
| + | * biblioteca ce asigură funcționalitatea de acces la date; | ||
| + | * URL-ul pentru asigurarea conexiunii la baza de date; | ||
| + | * strategia de generare a tabelelor (//Create//, //Drop and Create//, //None//); | ||
| + | * strategia de validare (//Auto//, //Callback//, //None//); | ||
| + | * mecanismul de gestiune a zonei de memorie tampon partajate (//All//, //None//, //Enable Selective//, //Disable Selective//, //Unspecified//); | ||
| + | * clasele entitate care vor fi gestionate (pentru acestea, se indică calea lor completă, inclusiv pachetul din care fac parte). | ||
| + | |||
| + | {{ :laboratoare:laborator02:netbeans02.png?nolink&700 }} | ||
| ===== Activitate de Laborator ===== | ===== Activitate de Laborator ===== | ||
| Line 756: | Line 1142: | ||
| student@aipi2015:~$ git clone https://www.github.com/aipi2015/Laborator02.git | student@aipi2015:~$ git clone https://www.github.com/aipi2015/Laborator02.git | ||
| </code> | </code> | ||
| + | |||
| + | <note important>Modificați în fișierul ''persistence.xml'' din directorul ''resources%%/%%META-INF'' informațiile necesare obținerii drepturilor de acces la baza de date (nume de utilizator, parola).</note> | ||
| + | |||
| + | **1**. Să se implementeze metoda ''getPersistentEntitySize()'' din clasa ''PersistentEntityManager'' a pachetului ''ro.pub.cs.aipi.lab02.businesslogic'' care furnizează numărul de obiecte al unei entități persistente. | ||
| + | |||
| + | <spoiler|Indicații de Rezolvare> | ||
| + | Metoda statică ''getEntityManagerFactory()'' din clasa ''Utilities'' furnizează o fabrică pentru obiecte de gestiune a entităților, unică la nivelul întregii unități de persistență. Resursele ocupate de obiectul de tip ''EntityManager'' trebuie eliberate (prin apelul metodei ''close()'') dacă acesta nu mai este necesar. | ||
| + | Se va folosi un obiect de tip ''Query'' care va întoarce un singur rezultat. | ||
| + | Limbajul JPL implică folosirea denumirii clasei de tip entitate în locul denumirii tabelei. Se poate utiliza metoda ''getSimpleName()'' pentru obiectul ''persistentEntityType'' de tip ''Class''. | ||
| + | </spoiler> | ||
| + | |||
| + | **2**. Să se implementeze metoda ''getBookList()'' din clasa ''BookManager'' a pachetului ''ro.pub.cs.aipi.lab02.businesslogic'' care furnizează lista tuturor cărților din baza de date. | ||
| + | |||
| + | Pentru fiecare volum vor fi incluse următoarele informații: | ||
| + | * identificatorul; | ||
| + | * titlul; | ||
| + | * lista autorilor (în formatul ''prenume nume''): | ||
| + | * în cazul în care nu există nici un autor, se va afișa textul ''* * *''; | ||
| + | * în cazul în care există mai mulți autori, aceștia vor fi delimitați prin șirul de caractere '', '' (virgulă și spațiu); | ||
| + | * denumirea colecției; | ||
| + | * denumirea editurii; | ||
| + | * ediția; | ||
| + | * anul de apariție; | ||
| + | * țara. | ||
| + | |||
| + | Rezultatul acestei metode este o listă de obiecte de tip ''BookInformation'' care are drept proprietăți toate informațiile solicitate sub forma unor tipuri de date primitive din limbajul Java (sau wrappere ale acestora). | ||
| + | |||
| + | Este obligatoriu să se folosească Criteria API. | ||
| + | |||
| + | <spoiler|Indicații de Rezolvare> | ||
| + | Se încarcă tot conținutul entității persistente ''Book'' (folosind metoda ''getCollection()'' din clasa ''PersistentEntityManager''), parcurgându-se ulterior lista de rezultate pentru a se extrage informațiile necesare. Pentru unele proprietăți (lista de scriitori), vor fi necesare prelucrări suplimentare, care vor fi realizate direct pe obiectele Java. | ||
| + | Este necesar ca obiectul de tip ''EntityManager'' să fie menținut atâta vreme cât este necesar să se obțină obiecte de tip referință, acestea fiind încărcate leneș. Numai după ce toate informațiile au fost încărcate din baza de date, resursele ocupate de acesta pot fi eliberate. | ||
| + | </spoiler> | ||
| + | |||
| + | **3**. Să se implementeze metoda ''create()'' din clasa ''PersistentEntityManager'' a pachetului ''ro.pub.cs.aipi.lab02.businesslogic'', pentru a stoca un nou obiect într-o tabelă a bazei de date. <code java> | ||
| + | public Long create(T persistentEntity); | ||
| + | </code> | ||
| + | Metoda primește ca parametru un obiect de tip generic (derivat din ''PersistentEntity''), conținând toate proprietățile, mai puțin cheia primară (care va fi autogenerată) și întoarce identificatorul din baza de date al entității persistente respective. | ||
| + | |||
| + | <spoiler|Indicații de Rezolvare> | ||
| + | Nu uitați să folosiți o tranzacție, care asigură atomicitatea operației și un nivel de izolare corespunzător. | ||
| + | Identificatorul poate fi obținut numai după ce obiectul a fost stocat în baza de date, **în afara tranzacției** (cu alte cuvinte, după ce a fost apelată metoda ''commit()'' - sau ''flush()''). | ||
| + | </spoiler> | ||
| + | |||
| + | **4**. Să se implementeze metoda ''updateBookPresentationPriceForBooksWithMultipleFormats()'' din clasa ''BookPresentationManager'' a pachetului ''ro.pub.cs.aipi.lab02.businesslogic'' astfel încât să mărească cu un anumit procent prețul cărților care sunt disponibile într-un număr de formate (de prezentare) mai mare decât un anumit prag. <code java> | ||
| + | public List<BookPresentationInformation> updateBookPresentationPriceForBooksWithMultipleFormats(int numberOfFormats, double amount) | ||
| + | </code> | ||
| + | Metoda primește ca parametri procentul cu care este crescut prețul cărților precum și numărul de formate pe care trebuie să îl aibă și furnizează informații referitoare la prezentările cărților pentru care au fost actualizate, stocate ca proprietăți ale clasei ''BookPresentationInformation'': | ||
| + | * identificatorul din tabela ''book_presentation''; | ||
| + | * identificatorul cărții corespunzătoare; | ||
| + | * identificatorul formatului corespunzător; | ||
| + | * prețul după modificare. | ||
| + | |||
| + | Este de preferat să se folosească Criteria API, acolo unde este posibil. | ||
| + | |||
| + | <spoiler|Indicații de Rezolvare> | ||
| + | Operațiile de creare și de ștergere a unei tabele temporare vor fi realizate folosind interogări native, întrucât JPA nu oferă suport pentru astfel de operații. Întrucât actualizarea folosește informații din tabela temporară, acestea nefiind corespunzătoare unei entități, și această operație va fi realizată tot prin intermediul unor interogări native. | ||
| + | Se va utiliza Criteria API pentru a se determina lista cărților pentru care trebuie actualizat prețul precum și pentru a se determina informațiilor solicitate după operația de actualizare. | ||
| + | </spoiler> | ||
| + | |||
| + | **5**. Să se implementeze metoda ''deleteWritersWithoutBooks()'' din clasa ''WriterManager'' a pachetului ''ro.pub.cs.aipi.lab02.businesslogic''. Metoda furnizează numărul de înregistrări care au fost modificate. | ||
| + | |||
| + | Este obligatoriu să se folosească Criteria API. | ||
| + | |||
| + | <spoiler|Indicații de Rezolvare> | ||
| + | Pentru subinterogarea din clausa WHERE se va utiliza un obiect de tip ''SubQuery''. Aceasta va furniza numărul de înregistrări din entitatea ''Author'' corespunzătoare scriitorului respectiv, fiind necesar ca acesta să fie 0. | ||
| + | </spoiler> | ||
| + | |||
| + | **6**. Să se implementeze metoda ''getWritersBibliography()'' din clasa ''WritersManager'' a pachetului ''ro.pub.cs.aipi.lab02.businesslogic'' care furnizează lista scriitorilor care au un scris un anumit număr de cărți, dintre care la unele sunt unici autori iar pe altele le-au redactat în colaborare (oricare dintre aceste valori pot fi și nule). <code java> | ||
| + | public List<WriterInformation> getWritersBibliography(int numberOfBooksTotal, int numberOfBooksAlone, int numberOfBooksCollaboration) { | ||
| + | </code> | ||
| + | |||
| + | Rezultatul acestei metode este o listă de obiecte de tip ''WriterInformation'' care are drept proprietăți toate informațiile solicitate sub forma unor tipuri de date primitive din limbajul Java (sau wrappere ale acestora). | ||
| + | |||
| + | Se vor afișa prenumele și numele autorilor, lista cărților scrise (separate prin caracterul '';''), numărul total de cărți, numărul de cărți la care este unic autor, numărul de cărți redactate în colaborare cu alții. | ||
| + | |||
| + | Informațiile vor fi ordonate (crescător) în funcție de prenumele și numele scriitorilor. | ||
| + | |||
| + | <spoiler|Indicații de Rezolvare> | ||
| + | Se determină lista tuturor scriitorilor folosind metoda ''getCollection()'' din clasa ''PersistentEntityManager''. | ||
| + | Pentru fiecare scriitor în parte, se determină - prin intermediul unei interogări - lista tuturor cărților pe care aceștia le-au scris. În situația în care numărul lucărilor la care au participat corespunde pragului impus se calculează - prin intermediul altor interogări - numărul cărților la care sunt unici autori, respectiv numărul de cărți redactate în colaborare cu alții (pentru acestea este necesar să se utilizeze subinterogări care contorizează numărul de înregistrări din entitatea ''Author'' corespunzătoare unei cărți din lista celor pe care le-a redactat un scriitor). Dacă și aceste criterii respectă condițiile, informațiile sunt incluse în rezultat. | ||
| + | </spoiler> | ||
| + | |||
| + | **7**. Să se implementeze metoda ''makeSupplyOrderBasedOnStockPile()'' din clasa ''BookPresentationManager'' a pachetului ''ro.pub.cs.aipi.lab02.businesslogic'' care creează comenzi de aprovizionare pentru cărțile al căror stoc este inferior unui anumit prag, furnizat ca parametru. O comandă de aprovizionare este realizată pentru o anumită editură și conține toate cărțile furnizate de aceasta, având stocul care respectă condiția respectivă. <code java> | ||
| + | public List<SupplyOrderInformation> makeSupplyOrderBasedOnStockpile(int stockpile); | ||
| + | </code> | ||
| + | |||
| + | Rezultatul acestei metode este o listă de obiecte de tip ''SupplyOrderInformation'' care are drept proprietăți toate informațiile solicitate sub forma unor tipuri de date primitive din limbajul Java (sau wrappere ale acestora): identificatorul editurii, identificatorul pentru prezentarea cărții, respectiv cantitatea pentru care a fost realizată comanda de aprovizionare. | ||
| + | |||
| + | Este obligatoriu să se folosească Criteria API. | ||
| + | |||
| + | <spoiler|Indicații de Rezolvare> | ||
| + | Se indentifică acele formate de prezentare ale cărților pentru care stocul nu întrunește cantitatea minimă, acestea fiind ordonate în funcție de editură. Sortarea în funcție de mai multe criterii se realizează folosind o listă de obiecte de tip [[https://docs.oracle.com/javaee/7/api/javax/persistence/criteria/Order.html|javax.persistence.criteria.Order]]. Accesul la identificatorul editurii se face prin intermediul unui obiect ''Join<Collection, PublishingHouse>'' obținut pe baza operației de asociere (prin intermediul metodei ''join()'') ce pornește de la un obiect de tipul ''BookPresentation''. | ||
| + | Se parcurge această listă, creându-se o comandă de aprovizionare atunci când se întâlnește o editură nouă. O entitate corespunzătoare va fi stocată pentru fiecare volum în parte, cantitatea fiind determinată ca diferență între pragul minim și valoarea aflată în stoc. Pentru stocarea unei valori în baza de date se va utiliza metoda ''create()'' din clasele specifice, derivate din ''PersistentEntityManager'', pentru tipurile de date corespunzătoare (''SupplyOrderHeader'', respectiv ''SupplyOrderLine''). | ||
| + | Pentru generarea unui număr de identificare se poate utiliza metoda statică ''generateIdentificationNumber()'' din clasa ''Utilities'' pentru care se specifică stuctura: numărul de caractere de tip literă, respectiv numărul de caractere de tip cifră. | ||
| + | Lista înregistrărilor stocate se poate determina pe baza datei la care acestea au fost emise (data curentă). | ||
| + | |||
| + | <note important>Este necesar să se elibereze resursele alocate pentru obiectul de tip ''EntityManager'' între operațiile de scriere, respectiv de citire a informațiilor în baza de date, pentru a se asigura faptul că interogările furnizează înregistrări actualizate.</note> | ||
| + | </spoiler> | ||
| + | |||
| + | **8**. Să se implementeze metoda ''getBookListsWithStockpile()'' din clasa ''BookManager'' a pachetului ''ro.pub.cs.aipi.lab02.businesslogic'' care furnizează lista cărților pentru care suma stocurilor (determinate din toate formatele de prezentare posibile) depășește un anumit prag, furnizat ca parametru. <code java> | ||
| + | public List<BookInformationDetailed> getBooksListWithStockpile(int stockpile) | ||
| + | </code> | ||
| + | |||
| + | Pentru fiecare volum vor putea fi consultate următoarele informații: | ||
| + | * identificatorul; | ||
| + | * titlul și subtitlul; | ||
| + | * lista autorilor; | ||
| + | * lista categoriilor; | ||
| + | * lista formatelor; | ||
| + | * lista limbilor. | ||
| + | |||
| + | Rezultatul acestei metode este o listă de obiecte de tip ''BookInformationDetailed'' care are drept proprietăți toate informațiile solicitate sub forma unor tipuri de date primitive din limbajul Java (sau wrappere ale acestora | ||
| + | |||
| + | În cazul în care o listă este vidă, se va afișa valoarea ''null''. În cazul în care o listă conține mai multe elemente, acestea vor fi delimitate prin caracterul virgulă. | ||
| + | |||
| + | Este obligatoriu să se folosească Criteria API. | ||
| + | |||
| + | <spoiler|Indicații de Rezolvare> | ||
| + | Se determină cărțile pentru care suma stocurilor corespunzătoare diferitelor tipuri de prezentări întrunește condiția specificată. | ||
| + | Pentru fiecare carte în parte se determină informațiile solicitate. Datele precum formatul și limba vor fi obținute unei interogări adiționale prin care se realizează asocierea dintre entitățile ''Book'' și ''BookPresentation''. | ||
| + | </spoiler> | ||
| ===== Resurse ====== | ===== Resurse ====== | ||
| Line 776: | Line 1284: | ||
| ===== Soluții ===== | ===== Soluții ===== | ||
| - | TODO | + | [[https://github.com/aipi2015/Laborator02/tree/master/solutions/eclipse/02-BookStore-JPA|Proiect Eclipse]]\\ |
| + | [[https://github.com/aipi2015/Laborator02/tree/master/solutions/netbeans/02-BookStore-JPA|Proiect NetBeans]] | ||
