• 10 heures
  • Difficile

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 01/03/2022

Ajoutez vos données en BDD (CREATE)

La partie 2 du cours vous a permis d’apprendre à récupérer des données. Mais une application Java digne de ce nom va bien au-delà du simple affichage de données.

Dans le cadre du projet Carlib Assurances, il ne s’agit pas simplement de retourner les catégories, produits et commentaires, mais également de pouvoir créer, modifier ou supprimer les données. Nous allons donc voir dans cette partie de cours les opérations restantes du CRUD, à savoir : CREATE, UPDATE et DELETE.

Le premier besoin métier auquel nous allons nous attaquer est la nécessité de créer de nouveaux éléments en base de données.

Ajoutez des données simples

Encore une fois, Spring Data JPA sera à la hauteur de sa réputation et va grandement nous simplifier la tâche, et ainsi nous faire gagner du temps !

Tout comme pour la récupération de données, l’interface CrudRepository nous offre des méthodes déjà implémentées.

Reprenons la liste des méthodes accessibles que nous avions déjà observées dans la partie 2 chapitre 2 :

La fonctionnalité d’autocomplétion de l’IDE permet de visualiser toutes les méthodes accessibles via un objet.
Liste des méthodes accessibles via l’interface CrudRepository.

Commençons par créer une catégorie en base de données.

Très bien, comment je fais ?

Procédez en 3 étapes :

  1. Modifiez la classe CategoryService pour ajouter une méthode appelant la méthode save.

  2. Dans la méthode run du DataLayerApplication, instanciez un nouvel objet Category, et saisissez la valeur de ses attributs.

  3. Appelez la nouvelle méthode de la classe CategoryService, et transmettez en paramètre l’objet Category que nous venons de créer.

Allez, c’est parti !

Voici le code pour la classe CategoryService :

package com.openclassrooms.datalayer.service;
 
import java.util.Optional;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import com.openclassrooms.datalayer.model.Category;
import com.openclassrooms.datalayer.repository.CategoryRepository;
 
@Service
public class CategoryService {
 
	@Autowired
	private CategoryRepository categoryRepository;
	
	public Iterable<Category> getCategories() {
		return categoryRepository.findAll();
	}
	
	public Optional<Category> getCategoryById(Integer id) {
		return categoryRepository.findById(id);
	}
	
	public Category addCategory(Category category) {
		return categoryRepository.save(category);		
	}
 
}

Vous pouvez noter la nouvelle méthode addCategory. Encore une fois, elle sert de relais entre la couche d’interface qui utilise le service, et la couche repository qui communique avec la base de données.

Pourquoi retourner une Category alors que nous la lui fournissons en paramètre d’entrée ?

C’est une question pertinente ! En réalité, l’objet Category retourné par la méthode save() diffère de celui que vous avez fourni en paramètre. Spring Data JPA va saisir la valeur de l’ID généré en base de données pour cette nouvelle catégorie au sein de l’objet, et va vous retourner l’objet.

Ainsi, en retour d’une opération save(), vous obtenez l’objet en question complété avec son nouvel ID, et cela peut vous être utile. 

Passons maintenant à la classe DataLayerApplication :

package com.openclassrooms.datalayer;
 
import javax.transaction.Transactional;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
import com.openclassrooms.datalayer.model.Category;
import com.openclassrooms.datalayer.service.CategoryService;
import com.openclassrooms.datalayer.service.CommentService;
import com.openclassrooms.datalayer.service.ProductService;
 
@SpringBootApplication
public class DataLayerApplication implements CommandLineRunner {
	
	@Autowired
	private ProductService productService;
 
	@Autowired
	private CategoryService categoryService;
	
	@Autowired
	private CommentService commentService;
 
	public static void main(String[] args) {
		SpringApplication.run(DataLayerApplication.class, args);
	}
 
	@Override
	@Transactional
	public void run(String... args) throws Exception {
 
		categoryService.getCategories().forEach(
				category -> System.out.println(category.getName()));
		
		Category newCategory = new Category();
		newCategory.setName("Promotion");
		
		newCategory = categoryService.addCategory(newCategory);
		
		categoryService.getCategories().forEach(
				category -> System.out.println(category.getName()));		
 
	}
 
}

Ligne 35 : J’affiche une première fois la liste des catégories présentes en base de données.

Lignes 38 et 39 : J’instancie un objet Category et je lui définis un nom. Le nom étant la seule information d’une catégorie (en dehors des relations), je n’ai rien d’autre à spécifier.

Ligne 41 : J’appelle la méthode addCategory créée précédemment dans la classe CategoryService.

Ligne 43 : J’affiche de nouveau les catégories présentes en base de données, et confirme la bonne création de ma nouvelle catégorie.

Vous en conviendrez, l’ajout d’une catégorie en base n’a rien eu de complexe. 

À vous de jouer !

Essayez d’implémenter l’ajout d’un Product en base de données. Vous vous souvenez des étapes ? Voici un petit aide-mémoire :

  1. Ajoutez une méthode addProduct dans la classe ProductService.

  2. Dans la méthode run du DataLayerApplication, créez un nouveau produit et définissez la valeur de ses attributs (name, description, cost).

  3. Appelez la nouvelle méthode de la classe ProductService pour persister le nouvel objet en base de données.

Vous avez réussi ? Bravo ! 

Pour la correction, vous pouvez récupérer le code dans le repository à la branche p3c1.

Ajoutez des données en tirant profit des relations

Pour l’instant, nous n’avons pas traité de la question des relations : la catégorie sauvegardée n’avait pas de produits associés, et le produit n’avait pas de commentaires ou de catégories associés.

Cependant, Carlib Assurances nous a informés qu’à la création d’un produit, nous voulons également indiquer les catégories existantes auxquelles le produit appartiendra !

Il est donc important de savoir intégrer les relations lors de l’insertion d’un objet en base de données, et ainsi de tirer profit du mécanisme des cascades.

Ce mécanisme permet d’effectuer une opération sur une entité associée à notre entité manipulée. En fonction du CascadeType défini sur la relation, toutes les opérations seront exécutées en cascade, ou bien seulement certaines.

La différence n’est pas si grande avec ce que nous avons fait dans la section précédente, mais laissez-moi vous présenter le code à travers un screencast :

Comme vous l’avez peut-être remarqué, je n’ai eu qu’à modifier la classe DataLayerApplication :

package com.openclassrooms.datalayer;
 
import javax.transaction.Transactional;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
 
import com.openclassrooms.datalayer.model.Category;
import com.openclassrooms.datalayer.model.Product;
import com.openclassrooms.datalayer.service.CategoryService;
import com.openclassrooms.datalayer.service.CommentService;
import com.openclassrooms.datalayer.service.ProductService;
 
@SpringBootApplication
public class DataLayerApplication implements CommandLineRunner {
 
	@Autowired
	private ProductService productService;
 
	@Autowired
	private CategoryService categoryService;
 
	@Autowired
	private CommentService commentService;
 
	public static void main(String[] args) {
		SpringApplication.run(DataLayerApplication.class, args);
	}
 
	@Override
	@Transactional
	public void run(String... args) throws Exception {
 
		categoryService.getCategories().forEach(
				category -> System.out.println(category.getName()));
		
		Category newCategory = new Category();
		newCategory.setName("Promotion");
		
		newCategory = categoryService.addCategory(newCategory);
		
		categoryService.getCategories().forEach(
				category -> System.out.println(category.getName()));
		
		Product newProduct = new Product();
		newProduct.setName("AssuranceAuTiersFidelite");
		newProduct.setDescription("Les garanties de l'assurance au tiers à un prix moindre grâce à votre fidélité!");
		newProduct.setCost(1100);
		
		newCategory.addProduct(newProduct);
		
		newProduct = productService.addProduct(newProduct);
		
		productService.getProducts().forEach(
				product -> System.out.println(product.getName()));
 
		newProduct.getCategories().forEach(
				category -> System.out.println(category.getName()));
	}
 
}
 

Lignes 36-45 : Une catégorie a été créée.

Lignes 47-50 : J’instancie le nouveau produit et lui définis ses valeurs.

Ligne 52 : J’utilise la méthode utilitaire créée dans la partie 2 chapitre 4 pour ajouter le produit à la catégorie existante. L’avantage de cette méthode utilitaire est qu’elle va également ajouter la catégorie au sein du produit. Opération rendue nécessaire par la bidirectionnalité de cette relation.

Ligne 54 : J’appelle la méthode addProduct pour déclencher la persistance.

Lignes 59-60 : Je me sers de l’objet retourné par la méthode addProduct pour afficher l’ensemble des catégories de cet objet. Je vérifie ainsi que la catégorie a bien été associée à mon nouveau produit.

À vous de jouer !

Votre mission, si vous l’acceptez, est d’implémenter la création d’un nouveau commentaire en prenant en compte sa relation avec l’entité Product.

Un petit indice : n’oubliez pas de tirer avantage de la méthode utilitaire addComment de la classe Product !

Avez-vous réussi ?! Oui, super ! 

Pour la correction, vous pouvez récupérer le code sur le repository à la branche p3c1.

Je profite de cet exercice pour mettre en avant un effet de la bidirectionnalité. Il y a en réalité dans ce cas 2 façons de faire. Je m’explique !

Le point de départ est de bien construire l’objet Comment et de mettre à jour l’objet Produit existant :

Product productAssuranceAuTiers = productService.getProductById(1).get();	
	Comment newComment = new Comment();
	newComment.setContent("Assurance peu intéressante.");
	productAssuranceAuTiers.addComment(newComment);

 Ici, la méthode utilitaire addComment va non seulement mettre à jour l’attribut produit de l’objet newComment, mais va également ajouter l’objet newComment au sein de la liste des commentaires de l’objet productAssuranceAuTiers.

Ainsi, cette méthode synchronise nos 2 objets. Par conséquent, vous pouvez appeler le save() tant sur le produit que sur le commentaire, et le résultat sera le même !

Enfin, comme dernier point de ce chapitre, sachez qu’il est possible de sauvegarder plusieurs nouveaux éléments simultanément, comme dans l’exemple ci-dessous où l’on sauvegarde un nouveau produit et une nouvelle catégorie en même temps :

Category newCategory = new Category();
	newCategory.setName("-25ans");
		
	Product newProduct = new Product();
	newProduct.setName("AssuranceAuTiers-25ans");
	newProduct.setDescription("Assurance au tiers réservée aux conducteurs de -25 ans.");
	newProduct.setCost(2000);
		
	newCategory.addProduct(newProduct);
	categoryService.addCategory(newCategory);

En résumé

  • L’interface CrudRepository donne accès à 2 méthodes pour persister nos objets en base de données :

    • save(S entity) ;

    • saveAll(Iterable<S> entities).

  • Les relations permettent de persister en cascade les objets.

  • Attention à tenir compte du type de relations quand les objets sont persistés en cascade.

Il nous reste encore 2 lettres du CRUD à traiter : UPDATE et DELETE. Retrouvez-moi dans le chapitre suivant ! 

Exemple de certificat de réussite
Exemple de certificat de réussite