Oggi ci occuperemo della mappatura One To Many in Hibernate. Esamineremo un esempio di mappatura One To Many in Hibernate utilizzando le annotazioni e la configurazione XML.
Mappatura One To Many in Hibernate
In termini semplici, la mappatura one to many significa che una riga in una tabella può essere mappata su più righe in un’altra tabella. Ad esempio, pensiamo a un sistema di carrelli in cui abbiamo un’altra tabella per gli oggetti. Un carrello può avere più oggetti, quindi qui abbiamo una mappatura one to many. Utilizzeremo lo scenario Carrello-Oggetti per il nostro esempio di mappatura one to many in Hibernate.
Mappatura One To Many in Hibernate – Configurazione del Database
Possiamo utilizzare un vincolo di chiave esterna per la mappatura one to many. Di seguito è riportato lo script del database per le tabelle Cart
e Items
. Sto utilizzando il database MySQL per l’esempio di mappatura one to many in 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;
Ecco il diagramma ER della tabella Carrello e Prodotti. La nostra configurazione del database è pronta, passiamo alla creazione di un esempio di progetto di mapping one-to-many con Hibernate. Prima di tutto, utilizzeremo una configurazione basata su XML e successivamente implementeremo il mapping one-to-many utilizzando le annotazioni di Hibernate e JPA.
Struttura del Progetto di Mapping One To Many di Hibernate
Crea un semplice progetto Maven in Eclipse o nel tuo IDE preferito, la struttura finale del progetto avrà un aspetto simile all’immagine sottostante.
Dependencies di Hibernate per Maven
Il nostro file pom.xml finale contiene le dipendenze per Hibernate e il driver MySQL. Hibernate utilizza il logging di JBoss e viene automaticamente aggiunto come dipendenza transitiva.
<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>
Si noti che sto utilizzando l’ultima versione di Hibernate 4.3.5.Final e la versione del driver MySQL in base all’installazione del mio database.
Modello di mapping uno a molti di Hibernate
Per le nostre tabelle Carrello e Articoli, abbiamo classi di modello per rifletterle. Carrello.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 richiede un costruttore senza argomenti
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;
}
}
Gli Articoli hanno una relazione molti a uno con il Carrello, quindi non è necessario avere una Collezione per l’oggetto Carrello.
Classe Utility SessionFactory di Hibernate
Abbiamo una classe utility per creare la SessionFactory di 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 {
// Crea la SessionFactory da 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;
}
}
File di configurazione XML di Hibernate
Il nostro file di configurazione xml di Hibernate contiene informazioni sul database e dettagli delle risorse di mappatura. 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>
Esempio di mapping uno a molti di Hibernate – Configurazione XML
Questa è la parte più importante del tutorial, vediamo come dobbiamo mappare le classi Cart e Items per il mapping uno a molti in 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 parte importante è l’elemento set
e l’elemento one-to-many
all’interno di esso. Notare che stiamo fornendo la chiave da utilizzare per il mapping uno a molti, ovvero 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>
Notare che da items a cart, è una relazione molti a uno. Quindi dobbiamo usare l’elemento many-to-one
per cart e stiamo fornendo il nome della colonna che verrà mappata con la chiave. Quindi, in base alla configurazione del mapping di Hibernate di Cart, verrà utilizzata la sua chiave cart_id per il mapping. Il nostro progetto per l’esempio di mapping uno a molti di Hibernate utilizzando il mapping XML è pronto, scriviamo un programma di test e controlliamo se funziona correttamente o meno.
Esempio di mapping uno a molti di Hibernate – Programma di 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{
//Ottieni Session
sessionFactory = HibernateUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
System.out.println("Session created");
//inizia transazione
tx = session.beginTransaction();
//Salva gli oggetti del modello
session.save(cart);
session.save(item1);
session.save(item2);
//Esegui transazione
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();
}
}
}
}
Si noti che è necessario salvare sia gli oggetti Carrello che gli oggetti Articoli uno per uno. Hibernate si occuperà dell’aggiornamento delle chiavi esterne nella tabella Articoli. Quando eseguiamo il programma sopra, otteniamo l’output seguente.
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
Si noti che Hibernate sta utilizzando la query di aggiornamento per impostare l’id_carrello nella tabella ARTICOLI.
Mappatura uno a molti di Hibernate con annotazioni
Ora che abbiamo visto come implementare la mappatura uno a molti in Hibernate utilizzando configurazioni basate su XML, vediamo come possiamo fare la stessa cosa utilizzando annotazioni JPA.
Esempio di mappatura uno a molti di Hibernate con annotazioni
Il file di configurazione di Hibernate è quasi lo stesso, tranne che l’elemento di mapping cambia perché stiamo utilizzando Classi per la mappatura uno a molti di hibernate usando annotazioni. 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 di utilità SessionFactory di Hibernate
La classe di utilità SessionFactory è quasi identica, è sufficiente utilizzare il nuovo file di configurazione di 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 {
// Crea la SessionFactory da 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;
}
}
Classi di modello di mapping One To Many di Hibernate con annotazioni
Dato che non abbiamo file di mapping basati su XML, tutte le configurazioni relative al mapping verranno effettuate utilizzando le annotazioni JPA nelle classi di modello. Se comprendi il mapping basato su XML, è molto semplice e simile. 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;
// Metodi Getter Setter per le proprietà
}
Il punto importante da notare è l’annotazione OneToMany
dove la variabile mappedBy
viene utilizzata per definire la proprietà nella classe Items1
che verrà utilizzata per il mapping. Quindi dovremmo avere una proprietà chiamata “cart1” nella classe Items1. Non dimenticare di includere tutti i metodi 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 richiede un costruttore senza argomenti
public Items1(){}
public Items1(String itemId, double total, int qty, Cart1 c){
this.itemId=itemId;
this.itemTotal=total;
this.quantity=qty;
this.cart1=c;
}
// Metodi Getter Setter
}
Il punto più importante nella classe sopra è l’annotazione ManyToOne
sulla variabile della classe Cart1 e l’annotazione JoinColumn
per fornire il nome della colonna per il mapping. Questo conclude il mapping one to many in Hibernate utilizzando le annotazioni nelle classi modello. Confrontalo con le configurazioni basate su XML; le troverai molto simili. Scriviamo ora un programma di test e eseguiamolo.
Esempio di programma di test di mapping one to many di Hibernate con annotazioni
Il nostro programma di test è simile alla configurazione basata su XML; stiamo solo usando le nuove classi per ottenere la sessione di Hibernate e salvare gli oggetti modello nel database. 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{
//Ottieni la sessione
sessionFactory = HibernateAnnotationUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
System.out.println("Session created");
//Inizia la transazione
tx = session.beginTransaction();
//Salva l'oggetto modello
session.save(cart);
session.save(item1);
session.save(item2);
//Conferma la transazione
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();
}
}
}
}
Quando eseguiamo il programma di test dell’esempio di mapping one to many di Hibernate con annotazioni, otteniamo il seguente output.
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
Questo è tutto per il mapping one to many di Hibernate; scarica il progetto di esempio dal link sottostante e fai ulteriori esperimenti.
Source:
https://www.digitalocean.com/community/tutorials/hibernate-one-to-many-mapping-annotation