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’appeler dept_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();
		}
	}