Aujourd’hui, nous allons examiner la correspondance de type One To Many dans Hibernate. Nous examinerons un exemple de correspondance Hibernate One To Many en utilisant des annotations et une configuration XML.
Correspondance One To Many dans Hibernate
En termes simples, la correspondance one to many signifie qu’une ligne dans une table peut être associée à plusieurs lignes dans une autre table. Par exemple, pensez à un système de panier où nous avons une autre table pour les articles. Un panier peut avoir plusieurs articles, nous avons donc ici une correspondance one to many. Nous utiliserons le scénario Cart-Items pour notre exemple de correspondance one to many dans Hibernate.
Correspondance One To Many dans Hibernate – Configuration de la base de données
Nous pouvons utiliser une contrainte de clé étrangère pour la correspondance one to many. Voici notre script de base de données pour les tables Cart
et Items
. J’utilise la base de données MySQL pour l’exemple de correspondance one to many dans Hibernate. setup.sql
CREATE TABLE `Cart` (
`cart_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`total` decimal(10,0) NOT NULL,
`name` varchar(10) DEFAULT NULL,
PRIMARY KEY (`cart_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
CREATE TABLE `Items` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`cart_id` int(11) unsigned NOT NULL,
`item_id` varchar(10) NOT NULL,
`item_total` decimal(10,0) NOT NULL,
`quantity` int(3) NOT NULL,
PRIMARY KEY (`id`),
KEY `cart_id` (`cart_id`),
CONSTRAINT `items_ibfk_1` FOREIGN KEY (`cart_id`) REFERENCES `Cart` (`cart_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
Voici le diagramme ER de la table Panier et Articles. Notre configuration de base de données est prête, passons maintenant à la création d’un exemple de projet de mappage One to Many avec Hibernate. Tout d’abord, nous utiliserons une configuration basée sur XML, puis nous implémenterons le mappage one to many en utilisant Hibernate et les annotations JPA.
Structure du projet de mappage Hibernate One to Many
Créez un projet Maven simple dans Eclipse ou votre IDE préféré, la structure finale du projet ressemblera à l’image ci-dessous.
Dépendances Maven Hibernate
Notre fichier pom.xml final contient les dépendances pour Hibernate et le pilote MySQL. Hibernate utilise le journal JBoss et il est automatiquement ajouté en tant que dépendances transitives.
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.journaldev.hibernate</groupId>
<artifactId>HibernateOneToManyMapping</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.3.5.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.0.5</version>
</dependency>
</dependencies>
</project>
Notez que j’utilise la dernière version de Hibernate 4.3.5.Final et la version du pilote MySQL en fonction de mon installation de base de données.
Classes de modèle de mappage Hibernate One To Many
Pour nos tables Cart et Items, nous avons des classes de modèle pour les refléter. Cart.java
package com.journaldev.hibernate.model;
import java.util.Set;
public class Cart {
private long id;
private double total;
private String name;
private Set<Items> items;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public double getTotal() {
return total;
}
public void setTotal(double total) {
this.total = total;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Items> getItems() {
return items;
}
public void setItems(Set<Items> items) {
this.items = items;
}
}
I am using Set of Items, so that every record is unique. We can also use List or Array for one to many mapping in hibernate. Items.java
package com.journaldev.hibernate.model;
public class Items {
private long id;
private String itemId;
private double itemTotal;
private int quantity;
private Cart cart;
//Hibernate nécessite un constructeur sans argument
public Items(){}
public Items(String itemId, double total, int qty, Cart c){
this.itemId=itemId;
this.itemTotal=total;
this.quantity=qty;
this.cart=c;
}
public String getItemId() {
return itemId;
}
public void setItemId(String itemId) {
this.itemId = itemId;
}
public double getItemTotal() {
return itemTotal;
}
public void setItemTotal(double itemTotal) {
this.itemTotal = itemTotal;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public Cart getCart() {
return cart;
}
public void setCart(Cart cart) {
this.cart = cart;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
Les Items ont une relation de plusieurs à un avec Cart, nous n’avons donc pas besoin de Collection pour l’objet Cart.
Classe utilitaire SessionFactory Hibernate
Nous avons une classe utilitaire pour créer une SessionFactory Hibernate. HibernateUtil.java
package com.journaldev.hibernate.util;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
public class HibernateUtil {
private static SessionFactory sessionFactory;
private static SessionFactory buildSessionFactory() {
try {
// Crée la SessionFactory à partir de hibernate.cfg.xml
Configuration configuration = new Configuration();
configuration.configure("hibernate.cfg.xml");
System.out.println("Hibernate Configuration loaded");
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
System.out.println("Hibernate serviceRegistry created");
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
}
catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
ex.printStackTrace();
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
if(sessionFactory == null) sessionFactory = buildSessionFactory();
return sessionFactory;
}
}
Fichier XML de configuration Hibernate
Notre fichier de configuration hibernate.xml contient des informations sur la base de données et des détails de ressources de mappage. hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"https://hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password">pankaj123</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost/TestDB</property>
<property name="hibernate.connection.username">pankaj</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.show_sql">true</property>
<mapping resource="cart.hbm.xml"/>
<mapping resource="items.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Exemple de mappage Hibernate One To Many – Configuration XML
Ceci est la partie la plus importante du tutoriel, voyons comment mapper les classes Cart et Items pour un mappage un à plusieurs dans Hibernate. cart.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"https://hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.journaldev.hibernate.model">
<class name="Cart" table="CART" >
<id name="id" type="long">
<column name="cart_id" />
<generator class="identity" />
</id>
<property name="total" type="double">
<column name="total" />
</property>
<property name="name" type="string">
<column name="name" />
</property>
<set name="items" table="ITEMS" fetch="select">
<key>
<column name="cart_id" not-null="true"></column>
</key>
<one-to-many class="Items"/>
</set>
</class>
</hibernate-mapping>
La partie importante est l’élément set
et l’élément one-to-many
à l’intérieur. Remarquez que nous fournissons la clé à utiliser pour le mappage un à plusieurs, c’est-à-dire cart_id. items.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"https://hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="com.journaldev.hibernate.model">
<class name="Items" table="ITEMS">
<id name="id" type="long">
<column name="id" />
<generator class="identity" />
</id>
<property name="itemId" type="string">
<column name="item_id"></column>
</property>
<property name="itemTotal" type="double">
<column name="item_total"></column>
</property>
<property name="quantity" type="integer">
<column name="quantity"></column>
</property>
<many-to-one name="cart" class="Cart">
<column name="cart_id" not-null="true"></column>
</many-to-one>
</class>
</hibernate-mapping>
Remarquez que des éléments vers le panier, il s’agit d’une relation plusieurs à un. Nous devons donc utiliser l’élément many-to-one
pour le panier et nous fournissons le nom de la colonne qui sera mappée avec la clé. Donc, en fonction de la configuration de mappage Hibernate Cart, sa clé cart_id sera utilisée pour le mappage. Notre projet pour l’exemple de mappage Hibernate One To Many en utilisant la configuration XML est prêt, écrivons un programme de test et vérifions s’il fonctionne correctement ou non.
Exemple de mappage Hibernate One To Many – Programme de test
HibernateOneToManyMain.java
package com.journaldev.hibernate.main;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.hibernate.model.Cart;
import com.journaldev.hibernate.model.Items;
import com.journaldev.hibernate.util.HibernateUtil;
public class HibernateOneToManyMain {
public static void main(String[] args) {
Cart cart = new Cart();
cart.setName("MyCart");
Items item1 = new Items("I1", 10, 1, cart);
Items item2 = new Items("I2", 20, 2, cart);
Set itemsSet = new HashSet();
itemsSet.add(item1); itemsSet.add(item2);
cart.setItems(itemsSet);
cart.setTotal(10*1 + 20*2);
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
//Obtenir la session
sessionFactory = HibernateUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
System.out.println("Session created");
//commencer la transaction
tx = session.beginTransaction();
//Enregistrer les objets Model
session.save(cart);
session.save(item1);
session.save(item2);
//Valider la transaction
tx.commit();
System.out.println("Cart ID="+cart.getId());
}catch(Exception e){
System.out.println("Exception occured. "+e.getMessage());
e.printStackTrace();
}finally{
if(!sessionFactory.isClosed()){
System.out.println("Closing SessionFactory");
sessionFactory.close();
}
}
}
}
Remarquez que nous devons enregistrer les objets Cart et Items un par un. Hibernate se charge de mettre à jour les clés étrangères dans la table Items. Lorsque nous exécutons le programme ci-dessus, nous obtenons la sortie suivante.
Hibernate Configuration loaded
Hibernate serviceRegistry created
Session created
Hibernate: insert into CART (total, name) values (?, ?)
Hibernate: insert into ITEMS (item_id, item_total, quantity, cart_id) values (?, ?, ?, ?)
Hibernate: insert into ITEMS (item_id, item_total, quantity, cart_id) values (?, ?, ?, ?)
Hibernate: update ITEMS set cart_id=? where id=?
Hibernate: update ITEMS set cart_id=? where id=?
Cart ID=6
Closing SessionFactory
Remarquez que Hibernate utilise une requête de mise à jour pour définir l’ID du panier dans la table ITEMS.
Annotation de mappage Hibernate One To Many
Maintenant que nous avons vu comment implémenter une relation One To Many dans Hibernate en utilisant des configurations basées sur XML, voyons comment nous pouvons faire la même chose en utilisant des annotations JPA.
Exemple d’annotation de mappage Hibernate One To Many
Le fichier de configuration Hibernate est presque identique, à l’exception du changement de l’élément de mappage car nous utilisons des classes pour le mappage Hibernate One To Many en utilisant des annotations. hibernate-annotation.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"https://hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password">pankaj123</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost/TestDB</property>
<property name="hibernate.connection.username">pankaj</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.show_sql">true</property>
<mapping class="com.journaldev.hibernate.model.Cart1"/>
<mapping class="com.journaldev.hibernate.model.Items1"/>
</session-factory>
</hibernate-configuration>
Classe utilitaire SessionFactory Hibernate
La classe utilitaire SessionFactory est presque identique, nous devons juste utiliser le nouveau fichier de configuration Hibernate. HibernateAnnotationUtil.java
package com.journaldev.hibernate.util;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
public class HibernateAnnotationUtil {
private static SessionFactory sessionFactory;
private static SessionFactory buildSessionFactory() {
try {
// Créez la SessionFactory à partir de hibernate-annotation.cfg.xml
Configuration configuration = new Configuration();
configuration.configure("hibernate-annotation.cfg.xml");
System.out.println("Hibernate Annotation Configuration loaded");
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
System.out.println("Hibernate Annotation serviceRegistry created");
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
}
catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
ex.printStackTrace();
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
if(sessionFactory == null) sessionFactory = buildSessionFactory();
return sessionFactory;
}
}
Classes de modèle d’annotations de mappage Hibernate One To Many
Étant donné que nous n’avons pas de fichiers de mappage basés sur XML, toutes les configurations liées au mappage seront effectuées à l’aide d’annotations JPA dans les classes de modèle. Si vous comprenez le mappage basé sur XML, c’est très simple et similaire. Cart1.java
package com.journaldev.hibernate.model;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name="CART")
public class Cart1 {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="cart_id")
private long id;
@Column(name="total")
private double total;
@Column(name="name")
private String name;
@OneToMany(mappedBy="cart1")
private Set items1;
// Méthodes Getter Setter pour les propriétés
}
Point important à noter, l’annotation OneToMany
où la variable mappedBy
est utilisée pour définir la propriété dans la classe Items1
qui sera utilisée à des fins de mappage. Nous devons donc avoir une propriété nommée « cart1 » dans la classe Items1. N’oubliez pas d’inclure toutes les méthodes getter-setter. Items1.java
package com.journaldev.hibernate.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name="ITEMS")
public class Items1 {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private long id;
@Column(name="item_id")
private String itemId;
@Column(name="item_total")
private double itemTotal;
@Column(name="quantity")
private int quantity;
@ManyToOne
@JoinColumn(name="cart_id", nullable=false)
private Cart1 cart1;
//Hibernate nécessite un constructeur sans arguments
public Items1(){}
public Items1(String itemId, double total, int qty, Cart1 c){
this.itemId=itemId;
this.itemTotal=total;
this.quantity=qty;
this.cart1=c;
}
// Méthodes Getter Setter
}
Le point le plus important dans la classe ci-dessus est l’annotation ManyToOne
sur la variable de classe Cart1 et l’annotation JoinColumn
pour fournir le nom de colonne pour la correspondance. C’est tout pour la correspondance un à plusieurs en utilisant Hibernate avec des annotations dans les classes de modèle. Comparez-le avec les configurations basées sur XML, vous les trouverez très similaires. Écrivons un programme de test et exécutons-le.
Exemple de programme de test de correspondance un à plusieurs avec les annotations Hibernate
Notre programme de test est similaire à une configuration basée sur XML, nous utilisons simplement les nouvelles classes pour obtenir la session Hibernate et enregistrer les objets de modèle dans la base de données. HibernateOneToManyAnnotationMain.java
package com.journaldev.hibernate.main;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.hibernate.model.Cart1;
import com.journaldev.hibernate.model.Items1;
import com.journaldev.hibernate.util.HibernateAnnotationUtil;
public class HibernateOneToManyAnnotationMain {
public static void main(String[] args) {
Cart1 cart = new Cart1();
cart.setName("MyCart1");
Items1 item1 = new Items1("I10", 10, 1, cart);
Items1 item2 = new Items1("I20", 20, 2, cart);
Set itemsSet = new HashSet();
itemsSet.add(item1); itemsSet.add(item2);
cart.setItems1(itemsSet);
cart.setTotal(10*1 + 20*2);
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
// Obtenir la session
sessionFactory = HibernateAnnotationUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
System.out.println("Session created");
// Démarrer la transaction
tx = session.beginTransaction();
// Enregistrer l'objet de modèle
session.save(cart);
session.save(item1);
session.save(item2);
// Valider la transaction
tx.commit();
System.out.println("Cart1 ID="+cart.getId());
System.out.println("item1 ID="+item1.getId()+", Foreign Key Cart ID="+item1.getCart1().getId());
System.out.println("item2 ID="+item2.getId()+", Foreign Key Cart ID="+item1.getCart1().getId());
}catch(Exception e){
System.out.println("Exception occured. "+e.getMessage());
e.printStackTrace();
}finally{
if(!sessionFactory.isClosed()){
System.out.println("Closing SessionFactory");
sessionFactory.close();
}
}
}
}
Lorsque nous exécutons le programme de test d’exemple de correspondance un à plusieurs avec les annotations Hibernate ci-dessus, nous obtenons la sortie suivante.
Hibernate Annotation Configuration loaded
Hibernate Annotation serviceRegistry created
Session created
Hibernate: insert into CART (name, total) values (?, ?)
Hibernate: insert into ITEMS (cart_id, item_id, item_total, quantity) values (?, ?, ?, ?)
Hibernate: insert into ITEMS (cart_id, item_id, item_total, quantity) values (?, ?, ?, ?)
Cart1 ID=7
item1 ID=9, Foreign Key Cart ID=7
item2 ID=10, Foreign Key Cart ID=7
Closing SessionFactory
C’est tout pour la correspondance un à plusieurs avec Hibernate, téléchargez le projet d’exemple à partir du lien ci-dessous et faites quelques expériences supplémentaires.
Télécharger le projet de correspondance un à plusieurs avec Hibernate
Source:
https://www.digitalocean.com/community/tutorials/hibernate-one-to-many-mapping-annotation