Introduction au mapping objet-relationnel (correction)
Téléchargement des corrections
Manager & Lowers:
Work at:
Connexion à la base de données
Comme mentionné en début du sujet, un ORM doit être capable de se connecter à la base de données qui va stocker
les informations manipulées par l’application. Pour ce faire, il faut que le programmeur fournisse, dans un fichier de configuration,
les informations nécessaires à cette connexion. Dans le cas de JPA, c’est le fichier persistence.xml
dans src/main/ressources/META-INF
qui doit contenir cette information. On doit y retrouver notamment l’adresse où se trouve la base de données, et le login et mot de passe que
l’application doit utiliser pour se connecter.
Le fichier de configuration
Pour votre application, en analysant le contenu du fichier persistence.xml
, trouvez les informations suivantes :
- le nom de la base de données PostgreSQL qui sera utilisée –
comrec_db
- le login utilisé pour accéder à la base –
pguser
- le mot de passe correspondant à ce login –
pgpwd
- le mode d’interaction entre l’application et la base de données (propriété
ddl-generation
) –drop-and-create-tables
- le nom des classes Java dont les instances seront « persistées » (on dit qu’elles seront mappées dans la base de données) –
Dept.java
- le fournisseur JPA à utiliser –
org.eclipse.persistence.jpa.PersistenceProvider
Question 1
Quelles sont les tables de la base ? Quelles sont leur colonnes ? Quelles données elles contiennent ?
On a une table departments qui a trois colonnes (dept_no, dname, dept_loc) et 3 lignes avec 1, 2 et 3 comme dept_no
.
Question 2
Lancez l’exécution de l’application. Analysez à nouveau les tables de la base de données ? Y a t’il eu des changements ? Lesquels ?
On a une table departments avec trois colonnes (dept_no, dname, dept_loc) et 3 lignes avec 1, 2 et 3 comme dept_no
. Donc, pas de changements.
– OPTIONNAL – Question 3
Changez la valeur de la propriété ddl-generation
pourqu’elle soit none
. A l’aide de Docker Desktop supprimez le service db
et relancez le (docker compose up -d
). Analysez les tables de la base de données (nom des colonnes et contenu de la table). Lancez l’application et regardez à nouveau la base. Y a t’il eu des changements ? Lesquels ?
3 nouvelles lignes se sont ajouté aux 3 existantes dans la table departments : on a alors 6 lignes. Et les colonnes sont toujours les mêmes.
Mapping d’une classe
Mapping classe - table
Mapping attribut - colonne
Question 4
D’après les annotations dans la classe Dept.java
fournie, répondez aux questions suivantes :
- quel est le nom de table qui contiendra les instances de la classe ? –
departments
- quel est le nom de la colonne correspondant à l’attribut
dName
? –dname
- modifiez le nom de la colonne correspondant à l’attribut
dName
, elle doit s’appelerdept_name
–@Column(name="dept_name")
Contraintes de clé primaire
D’autres éléments d’une entité
Exercice 1
Mapping des associations entre classes
Question 5
Modifiez les classes Dept.java
et Emp.java
pour implémenter l’association work at
telle que décrite précédemment
(pensez à ajouter les accesseurs des nouveaux attributs et à modifier la méthode toString
qui donne une description de l’instance).
Exécutez l’application et vérifiez que les changements dans les tables de la base de données ont bien eu lieu.
Exercice 2
Modifiez la classe Emp.java
pour implémenter l’association manager-lowers
. Le nom de la clé étrangère doit être mngr_fk
(à nouveau, pensez à modifier la méthode toString
). Vérifiez que les changements dans la table employees
ont bien eu
lieu. Quels sont ces changements ?
L’Entity Manager
Le contexte transactionnel
Question 6
Complétez le code de la méthode createEmployees(EntityManager)
de la classe Main.java
. Elle doit permettre de créer trois employés (king
, jones
et smith
)
dans la base de données et doit afficher à la fin les employés existant dans la base de données.
private void createEmployees(EntityManager em) {
System.out.println("\n-- Start simple employees creation --");
Emp king, jones, smith;
System.out.println("==== Create employees in memory ====");
try {
king = new Emp("KING", "PRESIDENT", null, null,
new SimpleDateFormat("dd-mm-yy").parse("17-11-81"), 5000, 0);
jones = new Emp("JONES", "MANAGER", null, null,
new SimpleDateFormat("dd-mm-yy").parse("04-12-81"), 2975, 0);
smith = new Emp("SMITH", "CLERK", null, null,
new SimpleDateFormat("dd-mm-yy").parse("17-12-80"), 800, 0);
} catch (ParseException e) {
System.err.println("ERROR CREATING EMPLOYEES (DATE PARSING PB)");
return;
}
System.out.println("===== Persist employees data ====\n ");
em.getTransaction().begin();
try {
em.persist(king);
em.persist(jones);
em.persist(smith);
em.getTransaction().commit();
} catch (Exception e) {
em.getTransaction().rollback();
e.printStackTrace();
} finally { // Either if new employees are created or not, display the employees existing in
// the database
System.out.println("===== Display employees data =====");
Query q = em.createNativeQuery("select e from employees e");
List<Emp> empList = (List<Emp>) q.getResultList();
System.out.println(empList);
}
}
Les méthodes de l’Entity Manager
La méthode persist
La méthode find
Question 7
Ajoutez la méthode private void createDepartmentsWithEmployees(EntityManager em)
à la classe Main
.
private void createDepartmentWithEmployees(EntityManager em) {
System.out.println("\n-- Start departments with employees creation --");
System.out.println("==== Create departments in memory ====");
Dept research = new Dept("RESEARCH", "Brest");
Dept accounting = new Dept("ACCOUNTING", "Rennes");
System.out.println("==== Create employees in memory ====");
Emp king, jones, blake, scott, ford;
try {
king = new Emp("KING", "PRESIDENT", null, null,
new SimpleDateFormat("dd-mm-yy").parse("17-11-81"), 5000, 0);
jones = new Emp("JONES", "MANAGER", null, null,
new SimpleDateFormat("dd-mm-yy").parse("04-12-81"), 2975, 0);
blake = new Emp("BLAKE", "ANALYST", null, null,
new SimpleDateFormat("dd-mm-yy").parse("01-05-81"), 2850, 0);
scott = new Emp("SCOTT", "ANALYST", null, null,
new SimpleDateFormat("dd-mm-yy").parse("09-12-82"), 3000, 0);
ford = new Emp("FORD", "ANALYST", null, null,
new SimpleDateFormat("dd-mm-yy").parse("03-12-81"), 3000, 0);
} catch (ParseException e) {
System.err.println("ERROR CREATING EMPLOYEES (DATE PARSING PB)");
return;
}
System.out.println("===== Affect employees to department ====\n ");
king.setDept(research);
jones.setDept(research);
blake.setDept(accounting);
scott.setDept(accounting);
ford.setDept(accounting);
System.out.println("===== Add employees to department ====\n ");
research.affectEmp(king);
research.affectEmp(jones);
accounting.affectEmp(blake);
accounting.affectEmp(scott);
accounting.affectEmp(ford);
System.out.println("===== Affect a manager to employees ====\n ");
jones.setManager(king);
blake.setManager(king);
scott.setManager(jones);
ford.setManager(jones);
System.out.println("===== Affect collaborators to an employee ====\n ");
king.addLower(jones);
king.addLower(blake);
jones.addLower(scott);
jones.addLower(ford);
System.out.println("===== Persist departments and employees data ====\n ");
em.getTransaction().begin();
try {
em.persist(research);
em.persist(accounting);
em.persist(king);
em.persist(jones);
em.persist(blake);
em.persist(scott);
em.persist(ford);
em.getTransaction().commit();
} catch (Exception e) {
em.getTransaction().rollback();
e.printStackTrace();
} finally { // Either if new department is created or not, display the department
System.out.println("===== Display departments data =====");
System.out.println(em.createNativeQuery("select d from departments d").getResultList());
System.out.println("===== Display employees data =====");
System.out.println(em.createNativeQuery("select e from employees e").getResultList());
}
}
Question 8
Modifiez l’application pour qu’elle permette de trouver les collaborateurs d’un employé donné.
private Emp findEmployee(EntityManager em, int empno) {
System.out.println("\n-- Start employee search --");
Emp emp = null;
em.getTransaction().begin();
try {
emp = em.find(Emp.class, empno);
em.getTransaction().commit();
return emp;
} catch (Exception e) {
em.getTransaction().rollback();
e.printStackTrace();
}
return emp;
}
private Set<Emp> findCollaborators(EntityManager em, Emp emp) {
System.out.println("\n-- Start find employees whose manager is " +
emp.getName() + " --");
Set<Emp> collaborators = emp.getLowers();
return collaborators;
}
La méthode merge
Question 9
Modifiez l’application pour qu’elle permette d’affecter une commission (un montant) aux collaborateurs d’un employé donné.
private void affectCommission(EntityManager em, Set<Emp> collaborators, float totalCommission) {
// Affect a commission to the collaborators of the manager
System.out.println("\n-- Start affect commission --");
System.out.println("\n Affect commission to " + collaborators.size() + " employees");
// Principles:
// - Compute sum salaries
// - For each employee:
// * Compute individual commission
// * Update database table with the new commission
// - Display database for verification
int totalSalary = 0;
float commission = 0;
for (Emp emp : collaborators)
totalSalary += emp.getSalary();
System.out.println("\n\t- Salaries sum: " + totalSalary);
for (Emp emp : collaborators) {
commission = emp.getSalary() * totalCommission / totalSalary;
emp.setCommission(commission);
System.out.println("\t- Commission of " + commission + " euros for " + emp);
}
System.out.println("===== Update employees in database =====");
em.getTransaction().begin();
try {
for (Emp emp : collaborators)
em.merge(emp);
em.getTransaction().commit();
} catch (Exception e) {
em.getTransaction().rollback();
e.printStackTrace();
}
}