Oggi parleremo di One to One Mapping in Hibernate. Esamineremo un esempio di mapping One To One in Hibernate utilizzando l’annotazione e la configurazione XML.
Mappatura One to One in Hibernate
Molte volte, le tabelle del database sono associate tra loro. Ci sono molte forme di associazione – one-to-one, one-to-many e many-to-many sono a un livello più ampio. Queste possono essere ulteriormente suddivise in mapping unidirezionale e bidirezionale. Oggi esamineremo l’implementazione di Hibernate One to One Mapping utilizzando la configurazione XML così come utilizzando la configurazione con annotazione.
Esempio di configurazione di Hibernate One to One Mapping nel database
Prima di tutto, dovremmo configurare una mappatura uno a uno nelle tabelle del database. Creeremo due tabelle per il nostro esempio: Transazione e Cliente. Entrambe queste tabelle avranno una mappatura uno a uno. La Transazione sarà la tabella principale e utilizzeremo la Chiave esterna nella tabella Cliente per la mappatura uno a uno. Fornisco uno script MySQL, che è il database che sto utilizzando per questo tutorial. Se stai utilizzando un altro database, assicurati di modificare lo script di conseguenza.
-- Crea la tabella Transazione
CREATE TABLE `Transaction` (
`txn_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`txn_date` date NOT NULL,
`txn_total` decimal(10,0) NOT NULL,
PRIMARY KEY (`txn_id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;
-- Crea la tabella Cliente
CREATE TABLE `Customer` (
`txn_id` int(11) unsigned NOT NULL,
`cust_name` varchar(20) NOT NULL DEFAULT '',
`cust_email` varchar(20) DEFAULT NULL,
`cust_address` varchar(50) NOT NULL DEFAULT '',
PRIMARY KEY (`txn_id`),
CONSTRAINT `customer_ibfk_1` FOREIGN KEY (`txn_id`) REFERENCES `Transaction` (`txn_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Il diagramma delle relazioni di entità (ERD) della mappatura uno a uno tra le tabelle appare come nell’immagine sottostante. La nostra configurazione del database è pronta, passiamo ora al progetto di esempio di Hibernate One to One.
Struttura del progetto di esempio di mappatura uno a uno di Hibernate
Crea un semplice progetto Maven nel tuo IDE Java, sto usando Eclipse. La nostra struttura finale del progetto sarà simile all’immagine sottostante. Prima di tutto, esamineremo un esempio di mapping uno a uno di Hibernate basato su XML e poi implementeremo la stessa cosa utilizzando le annotazioni.
Dipendenze Maven di Hibernate
Il nostro file pom.xml finale sarà simile al seguente.
<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>HibernateOneToOneMapping</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>
Le dipendenze sono solo per Hibernate e per il driver Java di MySQL. Nota che sto utilizzando l’ultima versione di Hibernate 4.3.5.Final e il driver Java di MySQL in base alla versione del mio server di database MySQL (5.0.5). Hibernate 4 utilizza il logging di JBoss e viene importato automaticamente come dipendenza transitiva. Puoi confermarlo nelle dipendenze Maven del progetto. Se stai utilizzando versioni precedenti di Hibernate, potresti dover aggiungere le dipendenze di slf4j.
Classi di modello per il mapping uno a uno di Hibernate
Le classi di modello per il mapping uno a uno di Hibernate per riflettere le tabelle del database sarebbero simili a quanto segue.
package com.journaldev.hibernate.model;
import java.util.Date;
public class Txn {
private long id;
private Date date;
private double total;
private Customer customer;
@Override
public String toString(){
return id+", "+total+", "+customer.getName()+", "+customer.getEmail()+", "+customer.getAddress();
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public double getTotal() {
return total;
}
public void setTotal(double total) {
this.total = total;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
package com.journaldev.hibernate.model;
public class Customer {
private long id;
private String name;
private String email;
private String address;
private Txn txn;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Txn getTxn() {
return txn;
}
public void setTxn(Txn txn) {
this.txn = txn;
}
}
Dal momento che stiamo utilizzando la configurazione basata su XML per il mapping, le classi del modello sopra riportate sono semplici classi POJO o Java Beans con metodi getter-setter. Sto utilizzando il nome di classe Txn
per evitare confusione perché l’API di Hibernate ha un nome di classe come Transaction
.
Configurazione di mapping uno a uno di Hibernate
Creiamo i file di configurazione di mapping uno a uno di Hibernate per le tabelle Txn e Customer. txn.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>
<class name="com.journaldev.hibernate.model.Txn" table="TRANSACTION" >
<id name="id" type="long">
<column name="txn_id" />
<generator class="identity" />
</id>
<property name="date" type="date">
<column name="txn_date" />
</property>
<property name="total" type="double">
<column name="txn_total" />
</property>
<one-to-one name="customer" class="com.journaldev.hibernate.model.Customer"
cascade="save-update" />
</class>
</hibernate-mapping>
Il punto importante da notare qui sopra è l’elemento hibernate one-to-one
per la proprietà customer. customer.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>
<class name="com.journaldev.hibernate.model.Customer" table="CUSTOMER">
<id name="id" type="long">
<column name="txn_id" />
<generator class="foreign">
<param name="property">txn</param>
</generator>
</id>
<one-to-one name="txn" class="com.journaldev.hibernate.model.Txn"
constrained="true"></one-to-one>
<property name="name" type="string">
<column name="cust_name"></column>
</property>
<property name="email" type="string">
<column name="cust_email"></column>
</property>
<property name="address" type="string">
<column name="cust_address"></column>
</property>
</class>
</hibernate-mapping>
generator class=”foreign” è la parte importante che viene utilizzata per l’implementazione della chiave esterna di Hibernate.
File di configurazione di Hibernate
Ecco il file di configurazione di Hibernate per la configurazione di mapping di Hibernate basata su XML. 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="txn.hbm.xml"/>
<mapping resource="customer.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Il file di configurazione di Hibernate è semplice, contiene le proprietà di connessione al database e le risorse di mapping di Hibernate.
Utilità SessionFactory di Hibernate
Ecco la classe di utilità per creare un’istanza di SessionFactory di Hibernate.
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;
}
}
Ecco, scriviamo un programma di test per testare la configurazione XML di mapping uno a uno di Hibernate.
Programma di test per la configurazione XML di mapping uno a uno di Hibernate
Nel programma di test dell’esempio di mapping uno a uno di Hibernate, prima creeremo l’oggetto Txn e lo salveremo. Una volta salvato nel database, utilizzeremo l’id generato per recuperare l’oggetto Txn e stamparlo.
package com.journaldev.hibernate.main;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.hibernate.model.Customer;
import com.journaldev.hibernate.model.Txn;
import com.journaldev.hibernate.util.HibernateUtil;
public class HibernateOneToOneMain {
public static void main(String[] args) {
Txn txn = buildDemoTransaction();
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
// Ottenere la Sessione
sessionFactory = HibernateUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
System.out.println("Session created");
// Iniziare la transazione
tx = session.beginTransaction();
// Salvare l'oggetto Model
session.save(txn);
// Confermare la transazione
tx.commit();
System.out.println("Transaction ID="+txn.getId());
// Ottenere i dati della transazione salvata
printTransactionData(txn.getId(), sessionFactory);
}catch(Exception e){
System.out.println("Exception occured. "+e.getMessage());
e.printStackTrace();
}finally{
if(!sessionFactory.isClosed()){
System.out.println("Closing SessionFactory");
sessionFactory.close();
}
}
}
private static void printTransactionData(long id, SessionFactory sessionFactory) {
Session session = null;
Transaction tx = null;
try{
// Ottenere la Sessione
sessionFactory = HibernateUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
// Iniziare la transazione
tx = session.beginTransaction();
// Salvare l'oggetto Model
Txn txn = (Txn) session.get(Txn.class, id);
// Confermare la transazione
tx.commit();
System.out.println("Transaction Details=\n"+txn);
}catch(Exception e){
System.out.println("Exception occured. "+e.getMessage());
e.printStackTrace();
}
}
private static Txn buildDemoTransaction() {
Txn txn = new Txn();
txn.setDate(new Date());
txn.setTotal(100);
Customer cust = new Customer();
cust.setAddress("Bangalore, India");
cust.setEmail("[email protected]");
cust.setName("Pankaj Kumar");
txn.setCustomer(cust);
cust.setTxn(txn);
return txn;
}
}
Ora, quando eseguiamo il programma di test di mapping uno a uno di Hibernate sopra, otteniamo il seguente output.
Hibernate Configuration loaded
Hibernate serviceRegistry created
Session created
Hibernate: insert into TRANSACTION (txn_date, txn_total) values (?, ?)
Hibernate: insert into CUSTOMER (cust_name, cust_email, cust_address, txn_id) values (?, ?, ?, ?)
Transaction ID=19
Hibernate: select txn0_.txn_id as txn_id1_1_0_, txn0_.txn_date as txn_date2_1_0_, txn0_.txn_total as txn_tota3_1_0_,
customer1_.txn_id as txn_id1_0_1_, customer1_.cust_name as cust_nam2_0_1_, customer1_.cust_email as cust_ema3_0_1_,
customer1_.cust_address as cust_add4_0_1_ from TRANSACTION txn0_ left outer join CUSTOMER customer1_ on
txn0_.txn_id=customer1_.txn_id where txn0_.txn_id=?
Transaction Details=
19, 100.0, Pankaj Kumar, [email protected], Bangalore, India
Closing SessionFactory
Come puoi vedere, funziona bene e siamo in grado di recuperare i dati da entrambe le tabelle utilizzando l’id di transazione. Controlla l’SQL utilizzato da Hibernate internamente per ottenere i dati, sta utilizzando join per ottenere i dati da entrambe le tabelle.
Mapping uno a uno di Hibernate con annotazioni
Nella sezione precedente, abbiamo visto come utilizzare la configurazione basata su XML per il mapping uno a uno di Hibernate, ora vediamo come possiamo utilizzare JPA e le annotazioni di Hibernate per ottenere lo stesso risultato.
File di configurazione di Hibernate
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.Txn1"/>
<mapping class="com.journaldev.hibernate.model.Customer1"/>
</session-factory>
</hibernate-configuration>
La configurazione di Hibernate è semplice, come puoi vedere ho due classi di modello che useremo con le annotazioni – Txn1
e Customer1
.
Esempio di classi di modello per il mapping uno a uno di Hibernate con annotazioni
Per la configurazione dell’annotazione di mappatura uno a uno di Hibernate, le classi modello sono la parte più importante. Vediamo come appaiono le nostre classi modello.
package com.journaldev.hibernate.model;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.hibernate.annotations.Cascade;
@Entity
@Table(name="TRANSACTION")
public class Txn1 {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="txn_id")
private long id;
@Column(name="txn_date")
private Date date;
@Column(name="txn_total")
private double total;
@OneToOne(mappedBy="txn")
@Cascade(value=org.hibernate.annotations.CascadeType.SAVE_UPDATE)
private Customer1 customer;
@Override
public String toString(){
return id+", "+total+", "+customer.getName()+", "+customer.getEmail()+", "+customer.getAddress();
}
//Metodi Getter-Setter, omessi per chiarezza
}
Si noti che la maggior parte delle annotazioni proviene da Java Persistence API perché Hibernate ne fornisce l’implementazione. Tuttavia, per la cascata, dovremmo utilizzare l’annotazione Hibernate org.hibernate.annotations.Cascade
e l’enum org.hibernate.annotations.CascadeType
.
package com.journaldev.hibernate.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
@Entity
@Table(name="CUSTOMER")
public class Customer1 {
@Id
@Column(name="txn_id", unique=true, nullable=false)
@GeneratedValue(generator="gen")
@GenericGenerator(name="gen", strategy="foreign", parameters={@Parameter(name="property", value="txn")})
private long id;
@Column(name="cust_name")
private String name;
@Column(name="cust_email")
private String email;
@Column(name="cust_address")
private String address;
@OneToOne
@PrimaryKeyJoinColumn
private Txn1 txn;
//Metodi Getter-Setter
}
Si noti che avremmo bisogno di @GenericGenerator
in modo che l’id venga utilizzato dalla txn anziché generarlo.
Classe di utilità di Hibernate SessionFactory
La creazione di SessionFactory è indipendente dal modo in cui forniamo la mappatura di Hibernate. La nostra classe di utilità per la creazione di SessionFactory appare come segue.
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;
}
}
Esempio di programma di test per la mappatura uno a uno di Hibernate con annotazioni
Ecco un semplice programma di test per il nostro esempio di mappatura uno a uno di Hibernate con annotazioni.
package com.journaldev.hibernate.main;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.hibernate.model.Customer1;
import com.journaldev.hibernate.model.Txn1;
import com.journaldev.hibernate.util.HibernateAnnotationUtil;
public class HibernateOneToOneAnnotationMain {
public static void main(String[] args) {
Txn1 txn = buildDemoTransaction();
SessionFactory sessionFactory = null;
Session session = null;
Transaction tx = null;
try{
//Ottieni Session
sessionFactory = HibernateAnnotationUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
System.out.println("Session created using annotations configuration");
//Avvia transazione
tx = session.beginTransaction();
//Salva l'oggetto Model
session.save(txn);
//Esegui la transazione
tx.commit();
System.out.println("Annotation Example. Transaction ID="+txn.getId());
//Ottieni i dati salvati della transazione
printTransactionData(txn.getId(), sessionFactory);
}catch(Exception e){
System.out.println("Exception occured. "+e.getMessage());
e.printStackTrace();
}finally{
if(sessionFactory != null && !sessionFactory.isClosed()){
System.out.println("Closing SessionFactory");
sessionFactory.close();
}
}
}
private static void printTransactionData(long id, SessionFactory sessionFactory) {
Session session = null;
Transaction tx = null;
try{
//Ottieni Session
sessionFactory = HibernateAnnotationUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
//Avvia transazione
tx = session.beginTransaction();
//Salva l'oggetto Model
Txn1 txn = (Txn1) session.get(Txn1.class, id);
//Esegui la transazione
tx.commit();
System.out.println("Annotation Example. Transaction Details=\n"+txn);
}catch(Exception e){
System.out.println("Exception occured. "+e.getMessage());
e.printStackTrace();
}
}
private static Txn1 buildDemoTransaction() {
Txn1 txn = new Txn1();
txn.setDate(new Date());
txn.setTotal(100);
Customer1 cust = new Customer1();
cust.setAddress("San Jose, USA");
cust.setEmail("[email protected]");
cust.setName("Pankaj Kr");
txn.setCustomer(cust);
cust.setTxn(txn);
return txn;
}
}
Ecco uno snippet di output quando eseguiamo il programma sopra.
Hibernate Annotation Configuration loaded
Hibernate Annotation serviceRegistry created
Session created using annotations configuration
Hibernate: insert into TRANSACTION (txn_date, txn_total) values (?, ?)
Hibernate: insert into CUSTOMER (cust_address, cust_email, cust_name, txn_id) values (?, ?, ?, ?)
Annotation Example. Transaction ID=20
Hibernate: select txn1x0_.txn_id as txn_id1_1_0_, txn1x0_.txn_date as txn_date2_1_0_, txn1x0_.txn_total as txn_tota3_1_0_,
customer1x1_.txn_id as txn_id1_0_1_, customer1x1_.cust_address as cust_add2_0_1_, customer1x1_.cust_email as cust_ema3_0_1_,
customer1x1_.cust_name as cust_nam4_0_1_ from TRANSACTION txn1x0_ left outer join CUSTOMER customer1x1_ on
txn1x0_.txn_id=customer1x1_.txn_id where txn1x0_.txn_id=?
Annotation Example. Transaction Details=
20, 100.0, Pankaj Kr, [email protected], San Jose, USA
Closing SessionFactory
Notare che l’output è simile alla configurazione XML basata su Hibernate One to One. Questo è tutto per l’esempio di mappatura Hibernate One to One, puoi scaricare il progetto finale dal link sottostante e provarlo per imparare di più.
Source:
https://www.digitalocean.com/community/tutorials/hibernate-one-to-one-mapping-example-annotation