PSI ModelProiect Partea4

21
Universitatea Alexandru Ioan Cuza din Iasi Facultatea de Economie si Administrarea Afacerilor An 3, Informatică Economică Proiectarea Sistemelor Informationale 3. Modelul fizic Până aici ne-am ocupat de: modelul conceptual, redat prin diagrama de clase ce includea entităţile persistente. Ea a fost realizată folosind standardul UML şi instrumentul Visual Paradigm. modelul logic al datelor, pentru care a fost adoptat modelul relaţional şi care a fost redat sub forma unei diagrame entitate-relaţie. Acest model a fost obţinut prin transformarea modelului conceptual. Acum ne vom ocupa de modelul fizic. El presupune implementarea modelelor conceptual şi logic folosind un limbaj de programare şi/sau un SGBD. Obţinerea modelului fizic de persistenţă presupune două transformări: 1) din diagrama de clase UML în clase folosind sintaxa limbajului de programare ales; 2) din diagrama entitate-relaţie în tabelele bazei de date folosind SGBD-ul ales pentru implementarea bazei de date. În ciclul de viaţă al aplicaţiilor moderne, aceste două tranformări au loc într-o manieră secvenţială, conform schemei din figura 8. Prima fază presupune transformarea diagramei de clase UML în limbajul de implementare a aplicatiei, iar în faza a doua se obţine schema bazei de date prin transformarea codului de implementare a claselor, rezultat în prima fază. Figura 8 Ciclul de transformare a structurilor de persistenţă Diagra ma UML Clase Java/.NE T etc Rela tii BD Transformare Transformare

description

PSI

Transcript of PSI ModelProiect Partea4

Page 1: PSI ModelProiect Partea4

Universitatea Alexandru Ioan Cuza din IasiFacultatea de Economie si Administrarea Afacerilor

An 3, Informatică EconomicăProiectarea Sistemelor Informationale

3. Modelul fizicPână aici ne-am ocupat de:

modelul conceptual, redat prin diagrama de clase ce includea entităţile persistente. Ea a fost realizată folosind standardul UML şi instrumentul Visual Paradigm.

modelul logic al datelor, pentru care a fost adoptat modelul relaţional şi care a fost redat sub forma unei diagrame entitate-relaţie. Acest model a fost obţinut prin transformarea modelului conceptual.

Acum ne vom ocupa de modelul fizic. El presupune implementarea modelelor conceptual şi logic folosind un limbaj de programare şi/sau un SGBD.

Obţinerea modelului fizic de persistenţă presupune două transformări:1) din diagrama de clase UML în clase folosind sintaxa limbajului de programare ales;2) din diagrama entitate-relaţie în tabelele bazei de date folosind SGBD-ul ales pentru

implementarea bazei de date.

În ciclul de viaţă al aplicaţiilor moderne, aceste două tranformări au loc într-o manieră secvenţială, conform schemei din figura 8. Prima fază presupune transformarea diagramei de clase UML în limbajul de implementare a aplicatiei, iar în faza a doua se obţine schema bazei de date prin transformarea codului de implementare a claselor, rezultat în prima fază.

Figura 8 Ciclul de transformare a structurilor de persistenţă

Ambele faze de transformare pot fi automatizate sau efectuate manual. Astfel:1) fiecare instrument de modelare UML oferă motoare de generare cod pe baza

diagramelor (forward engineering) sau de obţinere de diagrame pe baza codului existent (reverse engineering).

2) Limbajele moderne oferă cadre de lucru (frameworks) ORM (Object-Relational Mappings) care vor genera/sincroniza clasele de obiecte cu schema bazei de date pe baza informaţiilor suplimentare asociate claselor (prin cele două tehnici uzuale: adnotări sau fişiere XML).

Diagrama UML

Clase Java/.NET

etc Relatii

BD

Transformare

Transformare

Page 2: PSI ModelProiect Partea4

Universitatea Alexandru Ioan Cuza din IasiFacultatea de Economie si Administrarea Afacerilor

An 3, Informatică EconomicăProiectarea Sistemelor Informationale

Pentru implementarea modelului fizic am ales limbajul Java şi framework-ul de persistenţă JPA (Java Persistence API)1, versiunea de implementare Hibernate2 (open-source si utilizată pe scară largă in industrie). Trebuie reţinut că, maniera generală de abordare prezentată în continuare este perfect validă pentru orice alt limbaj de programare orientat pe obiecte. Astfel, fară îndoială, o implementare .NET (VB sau C#) va fi 99% similară deoarece există o implementare Hibernate si pentru .NET (vezi link-ul http://www.hibernate.org/).

3.1 Implementarea claselor (prima fază a transformării)

Implementarea completă exemplificată pentru diagrama de clase din figura 2 este disponibilă într-un proiect Eclipse (un mediu de dezvoltare foarte cunosctut utilizat si la disciplina Programare II) cu numele SGSM-Model. Paşi de efecutat:1) Dezarhivati continutul arhivei zip gasite pe Portal FEAA (disciplina PSI). Veţi obţine două

directoare cu cele două proiecte: modelul (SGSM-Model) şi o parte de implementare pentru interfaţa grafică (SGSM-GUI).

2) Creaţi un nou Workspace în directorul radacină al celor două proiecte.3) Importaţi cele două proiecte în respectivul workspace (File/import/General/ Existing projects

into workspace/ selectaţi directorul rădăcină/ bifaţi cele două proiecte).4) Motorul Hibernate este deja inclus în respectivul proiect (vezi directorul SGSM-Model/lib) iar

bibliotecile de clase sunt încărcate la nivelul proiectului (Project/Properties/Jaba build Path). Această operaţiune, de import al bibliotecilor “third parties” utilizate de un anumit proiect este, evident, obligatorie.

La deschiderea proiectului SGSM-Model veti vedea o structură precum cea din figura 9.

1 Recomandam cu insistență o scurtă revizuire a cunoștințelor dobandite la discilina Programare II 2 http://www.hibernate.org/

Page 3: PSI ModelProiect Partea4

Universitatea Alexandru Ioan Cuza din IasiFacultatea de Economie si Administrarea Afacerilor

An 3, Informatică EconomicăProiectarea Sistemelor Informationale

Figura 9 Structura proiectului SGSM-Model

Page 4: PSI ModelProiect Partea4

Universitatea Alexandru Ioan Cuza din IasiFacultatea de Economie si Administrarea Afacerilor

An 3, Informatică EconomicăProiectarea Sistemelor Informationale

În faza în care suntem acum, ne interesează doar clasele-entitate (pachetul ro.uaic.feaa.psi.sgsm.model.entities), care reflectă întocmai structurile din diagrama de clase din figura 2.

PENTRU MOMENT, vom ignora adnotările specifice ORM-JPA. La acestea vom reveni în secţiunea următoare.

Pentru că structurile sunt foarte simple (se apelează la cunoştinţe fundamentale de programare), nu vom descrie fiecare clasă, ci doar câteva reguli importante privind deciziile luate în implementarea anumitor aspecte şi codul aferent claselor respective. Astfel:

1) Toate clasele respectă şablonul de lucru Java Beans, care reflectă principiul încapsulării:a. Atributele sunt declarate cu vizibilitate private.b. Pentru fiecare atribut exista câte o metodă set/get publică (metode de acces si

modificare cu scop de a oferi acces la valoarea atributului privat).

Sablonul utilizat blocheaza accesul direct la atribut. Cu alte cuvinte, un client NU va putea executa o secvenţă de cod precum cea de mai jos (va obţine erori de compilare din pricina specificatorului de vizibilitate private):

Document x = new Document (); x.dataOperare = new Date(); sau Date data = x.dataOperare;

Pentru a accesa valoarea atributului dataOperare, clientul va fi obligat să utilizeze metodele publice corespunzatoare:

x.setDataOperare(new Date());Date data = x.getDataOperare();

Acest şablon este aplicabil în toate limbajele. Este recomandat a fi utilizat şi, în fapt, este omniprezent în toate aplicaţiile profesionale. Avantaje obţinute sunt:

a) Este foarte uşor de implementat un atribut de tip read-only. Astfel, să presupunem că, în exemplul de mai sus, dataOperare nu ar trebui să fie accesibilă la modificare. Valoarea acestui atribut ar trebui să fie automat asociată la crearea unui obiect nou Document (fie prin constructor fie prin asocierea directă la nivelul declaraţiei atributului), după care va fi posibilă doar citirea valorii, nu şi modificarea ei. Implementarea este foarte simplă: dacă nu declarăm o metodă publică de modificare (setDataOperare), va fi practic imposibilă modificarea valorii respective.

b) Este foarte uşor de adaugat cod suplimentar la momentul accesului sau modificării valorii, fără vreo implicaţie pentru client (nu va trebui să se modifice nimic la nivelul clientului). Astfel:

Page 5: PSI ModelProiect Partea4

Universitatea Alexandru Ioan Cuza din IasiFacultatea de Economie si Administrarea Afacerilor

An 3, Informatică EconomicăProiectarea Sistemelor Informationale

I. Presupunem că dorim implementarea unei restricţii prin care data operare trebuie să fie mai mare sau egală cu data documentului. Vom modifica metodele setDataOperare si setDataDocument astfel încât să verifice această restricţie şi să genereze o eroare în caz de încălcare a regulii (foarte simular conceptului de trigger la nivelul bazei de date).

II. Presupunem că dataOperare trebuie să fie prezentată public sub formă de dată calendaristică dar intern trebuie stocată prin intermediul a trei atribute zi, luna, an. Pentru a implementa o asemenea cerinţă:

i. Se declară 3 atribute private de tip Integer: zi, luna, anii. Metoda publică getDataOperare se modifcă pentru a construi şi returna

un obiect Date pe baza celor trei atribute interneiii. Metoda publică setDataOperare se modifcă pentru a extrage din

parametrul de tip Date primit cele trei parţi componente: zi, luna, an.

2) Implementarea claselor şi a relaţiilor M:1 unidirecţionale. Singurul aspect de remarcat în astfel de situaţii este includerea atributului gestiune de tip Gestiune pentru implementarea navigabilităţii dinspre clasa Consum spre clasa Gestiune.

@Entitypublic class Consum extends Document{

String numarComanda;String locConsum;@ManyToOneGestiune gestiune;

public String getNumarComanda() {return numarComanda;

}public void setNumarComanda(String numarComanda) {

this.numarComanda = numarComanda;}public String getLocConsum() {

return locConsum;}public void setLocConsum(String locConsum) {

this.locConsum = locConsum;}public Gestiune getGestiune() {

return gestiune;}public void setGestiune(Gestiune gestiune) {

this.gestiune = gestiune;}

}

Page 6: PSI ModelProiect Partea4

Universitatea Alexandru Ioan Cuza din IasiFacultatea de Economie si Administrarea Afacerilor

An 3, Informatică EconomicăProiectarea Sistemelor Informationale

3) Implementarea relaţiilor 1:M bidirecţionale. Atributele cu multiplicitatea mai mare de 1 se reprezintă sub forma colecţiilor. În cazul relaţiilor 1:M bidirecţionale, implementarea navigării relaţiei dinspre partea 1 (DocInsotitor) spre partea Multe (Receptie) impune includerea în clasa DocInsotitor a unui atribut de tip Receptie, care va avea multiplicitatea mai mare ca 1 şi care va fi implementat ca o colecţie. Colecţiile respectă un anumit şablon de implementare, astfel (luăm exemplul relaţiei între DocInsotitor si Receptie):

a. Colecţia se reprezintă intern folosind tipul cel mai convenabil prin intermediul unui atribut private. In cazul de faţă este folosită o implementare de tip Set, din două raţiuni:

i. Intr-o colecţie de tip Set obiectele sunt păstrate garantat într-o ordine bine definită (vezi cursul Programare II).

ii. Implementarea JPA Hibernate recomandă acest tip de colecţie pentru relaţiile One-To-Many (da, acest aspect este important în secţiunea următoare, dar venim să-l descriem aici).

b. Colecţia este apoi expusă public prin intermediul a cel puţin trei metode:i. Două metode pentru adăugare/ştergere elemente în/din colecţie.ii. Gestionarea relaţiei inverse (dinspre copil spre părinte).iii. O metodă de citire a colecţiei ce returnează o clonă a obiectului.

ATENŢIE – clientul nu trebuie niciodată să poată modifica în mod direct numărul de elemente al colecţiei (vezi restricţiile de implementare de mai sus privind managementul relaţiilor inverse). Ca urmare, vom expune colecţia sub forma unui tip uzual (List) dar de tip read-only.

Urmăriţi cu atenţie în exemplul reţinut mai jos următoarele aspecte:a) Cele 2 metode de actualizare a atributului receptii de tip colecţie: addReceptie şi

removeReceptie.b) În cadrul celor 2 metode se gestionează şi relaţia inversă prin invocarea metodei

setDocInsotitor din clasa Receptie.c) Metoda getReceptii care furnizează lista recepţiilor pentru un document însoţitor

sub forma unei liste read-only.

@Entitypublic class DocInsotitor extends Document {

private String mijlTransport;

@ManyToOneprivate DocInsotitor docInsotitorStornat;

@ManyToOneprivate DocInsotitor docInsotitorDeStornare;

@ManyToOne private Furnizor furnizor;

@OneToMany(mappedBy = "docInsotitor", cascade = CascadeType.ALL, fetch = FetchType.EAGER)

private Set<Receptie> receptii = new HashSet<Receptie>();

Page 7: PSI ModelProiect Partea4

Universitatea Alexandru Ioan Cuza din IasiFacultatea de Economie si Administrarea Afacerilor

An 3, Informatică EconomicăProiectarea Sistemelor Informationale

// ---------------metode pentru managementul colectiei receptii-----//

public void addReceptie(Receptie receptie) {this.receptii.add(receptie);receptie.setDocInsotitor(this);

}

public void addReceptie(Gestiune gestiune) {Receptie r = new Receptie();r.setGestiune(gestiune);this.addReceptie(r);

}

public void removeReceptie(Receptie receptie) {

this.receptii.remove(receptie);receptie.setDocInsotitor(null);

}

public List<Receptie> getReceptii() {return Collections. unmodifiableList ( new

LinkedList( this . receptii )) ;}

}

@Entitypublic class Receptie extends Document{

@ManyToOneDocInsotitor docInsotitor;@ManyToOneGestiune gestiune;

Boolean facturaPrimita;

public DocInsotitor getDocInsotitor() {return docInsotitor;

}public void setDocInsotitor(DocInsotitor docInsotitor) {

this.docInsotitor = docInsotitor;}

}

Să mai spunem că relaţiile de agregare sunt implementate de regulă ca fiind navigabile în ambele sensuri.

4) Implementarea relaţiilor M:M bidirecţionale. Implementarea acestor relaţii este asemănătoare cu situaţia anterioară doar că ambele atribute ce vor implementa relaţia de asociere vor fi de tip colecţie. În aplicaţia noastră nu există o astfel de situaţie însă, pentru exemplificare, vom analiza relaţia între clasele BunMaterial şi Categorie şi în care vom considera că un bun material se poate regăsi în mai multe categorii, iar o categorie va include mai multe bunuri materiale.

Page 8: PSI ModelProiect Partea4

Universitatea Alexandru Ioan Cuza din IasiFacultatea de Economie si Administrarea Afacerilor

An 3, Informatică EconomicăProiectarea Sistemelor Informationale

public class BunMaterial {...

private Collection<Categorie> categorii=new HashSet<Categorie>();

public void addCategorie(Categorie c) {if(! categorii.contains(c)) {

categorii.add(c);c.addBunMaterial(this);

}}

public void removeCategorie(Categorie c) {if(categorii.contains(c)) {

categorii.remove(c); c.removeBunMaterial(this);

}}

}

public class Categorie {

private String denumire;private Collection<BunMaterial> bunuri = new HashSet<BunMaterial>();

public void addBunMaterial(BunMaterial bun){if (!this.bunuri.contains(bun)) {

this.bunuri.add(bun);bun.addCategorie(this);

}}public void removeBunMaterial(BunMaterial bun){

if (this.bunuri.contains(bun)) {this.bunuri.remove(bun);bun.removeCategorie(this);

}}public Collection<BunMaterial> getBunuri() {

return Collections.unmodifiableCollection(bunuri);}

}

3.2 Maparea claselor şi a tabelelor bazei de date - tehnici ORM (a doua fază de transformare)

Page 9: PSI ModelProiect Partea4

Universitatea Alexandru Ioan Cuza din IasiFacultatea de Economie si Administrarea Afacerilor

An 3, Informatică EconomicăProiectarea Sistemelor Informationale

În această secţiune vom realiza cea de-a doua transformare pentru obţinerea modelului fizic, respectiv din codul de implementare a claselor (limbaj) în schema bazei de date. În acest scop se foloseşte un cadru de lucru ORM.

In secţiunea de faţă rămânem la modelul fizic şi proiectul Java SGSM-Model descris în paragraful anterior. Spuneam ca folosim cadrul de lucru JPA (Java Persistence API) si implementarea Hibernate, o implementare care este disponibilă atât pentru Java cât şi pentru .NET. Astfel, schema fizică a bazei de date prezentate în figura 3 poate fi creată în mod automat de catre motorul JPA (în cazul de faţă, Hibernate) prin transformarea modelului obiectual Java în relaţii corespunzătoare modelului relaţional.

Paşii de parcurs pentru a genera schema bazei de date sunt următorii:1. Se adauga informaţiile suplimentare de persistenţă la nivelul claselor-entitate. In

exemplul nostru am folosit metoda adnotărilor JPA, metodă care presupune adăugare de semantică JPA direct la nivelul clasei Java (în loc de fişiere de proprietăţi/XML separate) şi descrisă la disciplina Programare II.

2. Se adauga fisierul META-INF/persistence.xml – contine descrierea conexiunii catre baza de date. In exemplul nostru (vezi proiectul SGSM-Model) folosim baza de date PostgreSQL cu numele postgres (implict la instalare), instalata local, si o schema dedicata acestui exemplu cu numele sgsm (user si parola – acelasi sgsm). i) In cazul in care doriti sa folositi o alta baza de de date PostgreSQL (spre exemplu

cea pusa la dispozitie de faculate pentru disciplina BD I), va trebui sa modificati proprietatile:

<property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/postgres" />

<property name="hibernate.connection.username" value="sgsm" /><property name="hibernate.connection.password" value="sgsm" />

ii) In cazul in care doriti sa folositi un alt motor de baze de date va trebui sa modificati, pe langa proprietatile de mai sus, si tipul driverului si dialectul SQL utilizat. Atentie, in functie de motorul bazei de date, va trebui sa descarcati driverul de pe Internet si sa-l adaugati ca dependinta la proiect (driverul PostgreSQL este deja asociat proiectului)

iii) A se observa ca proiectul foloseste valoarea "update"3 pentru proprietatea esentiala ce va instrui comportamentul generatorului de schema de baze de date:<property name="hibernate.hbm2ddl.auto" value="update" />

Aceasta valoare va asigura actualizarea schemei bazei de date la fiecare modificare a modelului obiectual.

3. TRANSFORMAREA efectivă şi generarea schemei bazei de date, în cazul unui proiect POJO ca al nostru, va avea loc la execuţia primei comenzi JPA-QL (este vorba de un

3Vezi si http://stackoverflow.com/questions/438146/hibernate-question-hbm2ddl-auto-possible-values-and-what-they-do

Page 10: PSI ModelProiect Partea4

Universitatea Alexandru Ioan Cuza din IasiFacultatea de Economie si Administrarea Afacerilor

An 3, Informatică EconomicăProiectarea Sistemelor Informationale

SQL adaptat pentru nevoile modelului obiectual – de asemenea prezentat la disciplina Programare II). Astfel, este sufficient să scrieţi o clasă de test în care metoda main ar avea urmatorul continut:

4. public class FirstTest{5. public static void main(String[] args){6.7. EntityManager em = Persistence.createEntityManagerFactory(8. "SGSMPersistenceUnit").createEntityManager();9. em.createQuery("Select loc from Localitate loc").getResultList();10.11. }12. }

Nu vom insista aici asupra elementelor clasice JPA precum @Entity, @ManyToOne, @OneToMany. Toate acestea le aveti deja explicate in cursul Programare II pe care vă recomandăm să-l revizuiti cu atentie (sectiunea JPA, in special). Referitor la acestea, precizăm doar că s-a urmărit simplificarea la maximum a codului, astfel evitând declararea explicită a denumirilor de tabele şi atribute. Ca urmare, în schema generată vom regăsi exact aceleaşi denumiri ca şi în modelul obiectual. Această stare de fapt poate fi, evident, uşor de schimbat prin utilizarea atributelor corespunzătoare la nivelul adnotărilor.

În continuare dorim doar sa nuanţăm anumite decizii de proiectare:1) In primul rand, observam ca toate clasele entitate extind super-clasa AbstractEntity.

Această clasă este marcată @MappedSuperclass care instruieşte motorul JPA să nu genereze o tabelă distinctă ci să includă toate atributele clasei în tabelele generate pentru fiecare din sub-clasele acesteia. Prin intermediul acestei strategii sunt atinse următoarele aspecte critice privind proiectarea unui model JPA:a) Toate entităţile trebuie să deţină un ID (cheia primară) si este recomandat ca

această cheie să fie generată pe baza unei secvenţe în loc de a fi preluată din modelul domeniului. In speţă, o dată asociată, utilizatorul NU trebuie să poată modifica aceasta valoare a cheii primare. De asemenea, trebuie evitate cu orice preţ cheile compuse, acestea generând probleme deosebite în managementul general al aplicaţiilor client-server. Ca urmare, id-ul entităţilor este delcarat in superclasă şi va fi moştenit de subclase. Toate celelalte chei candidat din model vor fi declarate prin atributul unique (exemplu: Localitate.cod) care va determina generarea unei restricţii de unicitate la nivelul atributului.

b) Toate entităţile trebuie să prezinte informaţii generale privind: data crearii si modificarii, utilizatorul care a efectuat modificarea etc. Aceste atribute sunt, de asemenea, localizate la nivelul superclasei, unele dintre ele deţinând valori implicite.

c) Pentru că în aplicaţiile orientate pe date se folosesc in mod intensiv colecţii de obiecte, toate entităţile trebuie să implementeze în mod corect operatorii equals() şi hashCode() pe baza ID-ului. Iată de ce aceşti operatori vor fi implementaţi o singură dată la nivelul superclasei AbstractEntity.

Page 11: PSI ModelProiect Partea4

Universitatea Alexandru Ioan Cuza din IasiFacultatea de Economie si Administrarea Afacerilor

An 3, Informatică EconomicăProiectarea Sistemelor Informationale

d) Toate entităţile trebuie să ofere suport pentru mecanismul OptimisticLocking (crucial in aplicaţiile client-server). Hibernate oferă o implementare standard în acest sens pe baza atributului marcat @Version (în cazul nostru, atributul cu acelaşi nume).

e) In final, scopul fundamental al superclasei AbstractEntity este de a furniza structura şi comportamentul comune tuturor entităţilor, oricare ar fi acestea, în funcţie de necesităţi.

2) Relatiile de compunere din diagrama de clase, ce reprezintă modelul conceptual de structura, (figura 2) se traduc INTOTDEAUNA prin relaţii JPA de tip @OneToMany bidirecţionale (vezi DocumentLiniiDocument, unde există reciprocitatea @ManyToOne în clasa-copil. Relaţiile de asociere simple, unidirecţionale (vezi ReceptieGestiune) se traduc doar prin relaţii de tip ManyToOne la nivelul clasei-copil. Asemănarea cu mecanismul cheilor straine, in acest caz, este evidentă, singura diferenţă fiind aceea că în modelul relaţional referinţa se face prin valoare in timp ce in moelul obiectual, prin pointeri. Astfel, următoarele două propozţtii sunt echivalente :a) SQL: select g.denumire from Receptie r inner join Gestiune g on

r.idReceptie=g.idb) OO: receptie.getGestiune().getDenumire(); unde receptie este o variabilă de tip

Receptie. (inner join este echivalent cu navigabilitatea prin operatorul “.”)

3) Pentru relaţiile de moştenire, trebuie stabilită strategia de implementare la nivelul bazei de date. Există trei strategii: 1) o singură tabelă pentru toate clasele (atributele claselor-frunză vor avea valori null pentru tipurile vecine) – variantă care oferă optimizarea maximă a interogărilor dar mai puţin “ortodoxă” pentru evangheliştii modelului relaţional; 2) relaţii 1:1 între super-clasă şi sub-clase – cele mai “corecte” din punct de vedere al modelului relaţional – determină necesitatea unor operaţii de tip Join frecvente şi, ca urmare, o viteză de procesare inferioară variantei 1; 3) câte o tabelă pentru fiecare clasă-frunză – determină multiplicarea câmpurilor comune in tabele multiple şi necesitatea unor operaţii asambliste de tip UNION în cazul interogarilor pe tipurile-părinte. In exemplul de faţă s-a luat decizia adoptării stategiei 2. Aceasta abordare va determina generarea următoarelor relaţii 1:1 în BD: Document cu DocInsotitor, Receptie şi Consum.

In final, vom descoperi ca modelul generat automat este putin diferit fata de cel din figura 3, avand in vedere elementele de rafinare descrise mai sus, dar elementele generale raman aceleasi.

In continuare prezentăm partea de cod de implementare a claselor care conţine adnotările JPA şi implementarea clasei AbstractEntity.

public abstract class AbstractEntity implements Serializable {

private static final long serialVersionUID = -4803471783122679780L;

public static long getSerialVersionUID() {return serialVersionUID;

Page 12: PSI ModelProiect Partea4

Universitatea Alexandru Ioan Cuza din IasiFacultatea de Economie si Administrarea Afacerilor

An 3, Informatică EconomicăProiectarea Sistemelor Informationale

}

@Id@GeneratedValue(strategy = GenerationType.AUTO)@Column(name = "id")protected Long id;

/** * the @Version is used for Optimistic Locking mechanism */@Version@Column(name = "version")private Integer version;private String createdByUser;private String updatedByUser;

/** * most used for inheritance strategies */private String entity_type = this.getClass().getSimpleName();

@Temporal(value = TemporalType.TIMESTAMP)@Column(name = "dateCreated", nullable = false)private Date dateCreated=Calendar.getInstance().getTime();

@Temporal(value = TemporalType.TIMESTAMP)@Column(name = "dateUpdated", nullable = false)private Date dateUpdated=Calendar.getInstance().getTime();

/** * The default constructor is always needed for JPA. */public AbstractEntity() {

super();}

public AbstractEntity(Long id) {this();this.id = id;

}

/** * Provide the right equals implementation. Really mandatory. This * implementation is based on the object's ID. However, if the object

has * not been yet serialized to the DB, hence, no ID, then provide the

usual * implementation. */@Overridepublic boolean equals(Object obj) {

if (id == null)return super.equals(obj);

if (this == obj)return true;

if (obj == null)

Page 13: PSI ModelProiect Partea4

Universitatea Alexandru Ioan Cuza din IasiFacultatea de Economie si Administrarea Afacerilor

An 3, Informatică EconomicăProiectarea Sistemelor Informationale

return false;if (getClass() != obj.getClass())

return false;final AbstractEntity other = (AbstractEntity) obj;if (id == null) {

if (other.id != null)return false;

} else if (!id.equals(other.id))return false;

return true;}

/** * Provide the right hashcode implementation. Really mandatory. This * implementation is based on the object's ID. However, if the object

has * not been yet serialized to the DB, hence, no ID, then provide the

usual * implementation. */@Overridepublic int hashCode() {

if (id == null)return super.hashCode();

final int prime = 31;int result = 1;result = prime * result + ((id == null) ? 0 : id.hashCode());return result;

}

//---------------public GETTERS and SETTERS - the usual Java Beans approach-----------------------//

public String getCreatedByUser() {return createdByUser;

}

public Date getDateCreated() {return dateCreated;

}

public Date getDateUpdated() {return dateUpdated;

}

public String getEntity_type() {return entity_type;

}

public Long getId() {return id;

}

public String getUpdatedByUser() {return updatedByUser;

}

Page 14: PSI ModelProiect Partea4

Universitatea Alexandru Ioan Cuza din IasiFacultatea de Economie si Administrarea Afacerilor

An 3, Informatică EconomicăProiectarea Sistemelor Informationale

public Integer getVersion() {return version;

}

public void setCreatedByUser(String createdByUser) {this.createdByUser = createdByUser;

}

public void setDateCreated(Date dateCreated) {this.dateCreated = dateCreated;

}

public void setDateUpdated(Date dateUpdated) {this.dateUpdated = dateUpdated;

}

public void setEntity_type(String entity_type) {this.entity_type = entity_type;

}

public void setId(Long id) {this.id = id;

}

public void setUpdatedByUser(String updatedByUser) {this.updatedByUser = updatedByUser;

}

public void setVersion(Integer version) {this.version = version;

}

}

@Entitypublic class Consum extends Document{

String numarComanda;String locConsum;@ManyToOneGestiune gestiune;

}

@Entitypublic class DocInsotitor extends Document {

private String mijlTransport;

@ManyToOneprivate DocInsotitor docInsotitorStornat;

@ManyToOneprivate DocInsotitor docInsotitorDeStornare;

Page 15: PSI ModelProiect Partea4

Universitatea Alexandru Ioan Cuza din IasiFacultatea de Economie si Administrarea Afacerilor

An 3, Informatică EconomicăProiectarea Sistemelor Informationale

@ManyToOne private Furnizor furnizor;

@OneToMany(mappedBy = "docInsotitor", cascade = CascadeType.ALL, fetch = FetchType.EAGER)

private Set<Receptie> receptii = new HashSet<Receptie>();}

@Entity@Inheritance(strategy = InheritanceType.JOINED)public class Document extends AbstractEntity {

private String tipDocument;private String numarDocument;@Temporal(value = TemporalType.DATE)private Date dataDocument;@Temporal(value = TemporalType.TIMESTAMP)private Date dataOperare;@OneToMany(mappedBy = "document", cascade = CascadeType.ALL, fetch =

FetchType.EAGER)private Set<LinieDocument> liniiDocument = new HashSet<LinieDocument>();

}

@Entitypublic class Furnizor extends AbstractEntity {

@Column(unique = true)private String cod;private String nume;private String adresa;

private String CUI;private String banca;private String contBancar;private Double sold;@ManyToOne private Localitate localitate;

}

@Entitypublic class LinieDocument extends AbstractEntity {

Double cantitate=0.0; //valoarea null trebuie evitata cu orice pret aiciDouble pret=0.0; //valoarea null trebuie evitata cu orice pret aici@ManyToOneBunMaterial material;@ManyToOneDocument document;

}

Page 16: PSI ModelProiect Partea4

Universitatea Alexandru Ioan Cuza din IasiFacultatea de Economie si Administrarea Afacerilor

An 3, Informatică EconomicăProiectarea Sistemelor Informationale

public class Receptie extends Document{@ManyToOneDocInsotitor docInsotitor;@ManyToOneGestiune gestiune;

Boolean facturaPrimita;

}