Skip to main content

Spring Data JPA

Spring permet d'utiliser un ORM implémentant JPA et vous permet de ne pas avoir à écrire de requêtes SQL.

Par défaut, l'ORM utilisé par Spring est Hibernate qui implémente la norme JPA.

Bien qu'il soit possible d'utiliser XML pour faire du mapping avec Hibernate, la méthode privilégiée est l'utilisation d'annotations Java.

Mappings

@Entity pour indiquer à JPA que c'est une classe persistée en base

@Table optionnel pour indiquer un nom et des propriétés

@Entity
@Table( name = "articles" )
public class Article {
...
}

@Id permet d'indiquer la clé primaire

@GeneratedValue(strategy = GenerationType.IDENTITY) pour indiquer que la clé est générée automatiquement

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // avec un type serial en postgres
private Long id;

Par défaut, toutes les propriétés de l'objet seront mappées sur des colonnes.

@Column permet de préciser un nom.

@Transient permet d'indiquer qu'une propriété ne doit pas être mappée en base.

@Entity
@Table(name="articles")
public class Article {
private String titre;

@Column(name = "contenu")
private String corps;

@Transient
private String nePasStockerEnBase;
}

Il est possible de mapper les enum avec une colonne de type nombre ou texte.

@Enumerated(EnumType.ORDINAL) // ou EnumType.STRING
@Column(name = "statut")
private StatutArticle statut;

EnumType permet de dire si on stocke l'ordre de la valeur (ORDINAL -> int) ou son nom (STRING -> string)

L'annotation @ManyToOne permet de gérer les clés étrangères, dans l'entité qui possède la colonne FK.

@Entity
public class Commentaire {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String contenur;

@ManyToOne
@JoinColumn(name = "article_id")
private Article artcle;
}

@Entity
public class Article {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String titre;
}

Mappings

A l'inverse, il est possible dans l'entité qui ne possède pas la colonne de FK de faire un @OneToMany pour récupérer la liste des objets qui y font référence.

targetEntity permet de préciser la classe qui y fait référence, optionel car Java peut la détecter automatiquement à partir du type de la liste. L'attribut mappedBy permet de dire quel attribut porte le @ManyToOne dans l'entité cible. C'est optionnel également s'il est nommé à partir du nom de classe.

@Entity
public class Categorie {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@OneToMany(targetEntity=Article.class, mappedBy="categorie")
private List<Article> articles = new ArrayList<>();
}

Mappings

Enfin, le @ManyToMany permet de gérer les relations de type N:N. Il faut absolument une table intermédiaire pour stocker les relations.

@Entity
public class Article {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

// correspond à une table de jointure avec deux colonnes
// (id_article, id_label)
@ManyToMany
private List<Label> labels = new ArrayList<>();

}

@Entity
public class Label {}

TP9 - Création de mappings JPA

Reprenez vos classes Article et Categorie et ajoutez les annotations pour faire le mapping avec votre base de données.

  1. Indiquez que ces classes correspondent à des entités gérées en base avec @Entity
  2. Précisez quel attribut de chacune des classes correspond à la clé primaire avec @Id
  3. Indiquez le nom des colonnes pour quelques attributs avec @Column
  4. Gérez la foreign key entre Article et Category avec @ManyToOne et @OneToMany

Transactions

L'annotation @Transactional sur une classe ou une méthode publique permet de gérer automatiquement la transaction en base de données.

La transaction n'aura lieu que si la méthode est appelée depuis une autre classe.

// service transactionnel
@Service
@Transactional
public class MonService() {
public void methode1() {};
public void methode2() {};
}

// méthode transactionnelle
@Service
public class MonService() {
@Transactional
public void methode1() {};
}

Repository

L'interface JpaRepository<ENTITY, ID> proposée par Spring vous permet de créer un accès simple à vos données en base. En héritant de cette interface vous pourrez utiliser des méthodes de récupération et d'enregistrement des entités en base.

Méthodes héritées : findAll(), findById(), save(), etc.

Vous pouvez ajouter vos propres méthodes, la requête sera créée automatiquement en analysant le nom de la méthode.

@Repository
public interface ArticleRepository
extends JpaRepository<Article, Long> {

// génère select * from article where titre = :titre
List<Article> findByTitre(String titre);
}

Documentation

Possibilité de faire du JPQL / SQL et de garder la main sur les requêtes.

@Repository
public interface ArticleRepository
extends JpaRepository<Article, Long> {
@Query("select a from Article a where a.titre LIKE ?1")
Article findByTitre(String titre);
}

Documentation JPQL

TP10 - JpaRepository

Créez deux classes @Repository qui implémentent l'interface JpaRepository

  1. Pour l'entité Article
  2. Pour l'entité Categorie

Créez une méthode de controller qui permet d'envoyer un article en POST via Insomnia, et qui ensuite l'enregistre dans la base de données via son JpaRepository.