One To Many Mapping in Hibernate
Heute werfen wir einen Blick auf One To Many Mapping in Hibernate. Wir werden uns ein Beispiel für Hibernate One To Many Mapping mit Annotationen und XML-Konfiguration ansehen.
One To Many Mapping in Hibernate
Einfach ausgedrückt bedeutet One To Many Mapping, dass eine Zeile in einer Tabelle mit mehreren Zeilen in einer anderen Tabelle verknüpft werden kann.
Zum Beispiel denken Sie an ein Warenkorbsystem, in dem wir eine weitere Tabelle für Artikel haben. Ein Warenkorb kann mehrere Artikel haben, daher haben wir hier ein One To Many Mapping.
Wir verwenden das Warenkorb-Artikel-Szenario für unser Hibernate One To Many Mapping-Beispiel.
One To Many Mapping in Hibernate – Datenbankeinrichtung
Für One To Many Mapping können wir den Fremdschlüssel-Constraint verwenden. Unten finden Sie unser Datenbankskript für die Tabellen Warenkorb und Artikel. Ich verwende eine MySQL-Datenbank für das Hibernate One To Many Mapping-Beispiel.
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;
Unten sehen Sie das ER-Diagramm der Tabellen Warenkorb und Artikel.
Unsere Datenbankeinrichtung ist abgeschlossen. Lassen Sie uns nun ein Hibernate One To Many Mapping-Beispielprojekt erstellen. Zunächst verwenden wir eine XML-basierte Konfiguration, und dann implementieren wir das One To Many Mapping mit Hibernate und JPA-Anmerkungen.
Hibernate One To Many Mapping-Projektstruktur
Erstellen Sie ein einfaches Maven-Projekt in Eclipse oder Ihrer bevorzugten IDE. Die endgültige Projektstruktur sieht wie im folgenden Bild aus:
Hibernate Maven-Abhängigkeiten
Unsere endgültige pom.xml
-Datei enthält Abhängigkeiten für Hibernate und den MySQL-Treiber. Hibernate verwendet JBoss Logging, das automatisch als transitive Abhängigkeit hinzugefügt wird.
<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>
Beachten Sie, dass ich die neueste Hibernate-Version 4.3.5.Final und die MySQL-Treiberversion basierend auf meiner Datenbankinstallation verwende.
Hibernate One To Many Mapping Model-Klassen
Für unsere Tabellen Warenkorb und Artikel haben wir Modellklassen, die diese widerspiegeln.
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;
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 getItems() {
return items;
}
public void setItems(Set items) {
this.items = items;
}
}
Ich verwende eine Menge von Artikeln, sodass jeder Datensatz eindeutig ist. Wir können auch eine Liste oder ein Array für One To Many Mapping in Hibernate verwenden.
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 requires no-args constructor
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;
}
}
Artikel haben eine Many-to-One-Beziehung zu Warenkorb, sodass wir keine Sammlung für das Warenkorb-Objekt benötigen.
Hibernate SessionFactory Utility-Klasse
Wir haben eine Hilfsklasse zum Erstellen der Hibernate SessionFactory.
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 {
// Create the SessionFactory from 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;
}
}
Hibernate Konfigurations-XML-Datei
Unsere Hibernate-Konfigurations-XML-Datei enthält Datenbankinformationen und Mapping-Ressourcendetails.
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>
Hibernate One To Many Mapping Beispiel – XML-Konfiguration
Dies ist der wichtigste Teil des Tutorials. Lassen Sie uns sehen, wie wir sowohl Warenkorb- als auch Artikelklassen für One To Many Mapping in Hibernate abbilden müssen.
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>
Der wichtige Teil ist das set
-Element und das darin enthaltene one-to-many
-Element. Beachten Sie, dass wir einen Schlüssel für das One To Many Mapping angeben, d. h. 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>
NBeachten Sie, dass die Beziehung von Artikel zu Warenkorb eine Many-to-One-Beziehung ist. Daher müssen wir das
many-to-one
-Element für den Warenkorb verwenden und geben den Spaltennamen an, der mit dem Schlüssel abgeglichen wird. Basierend auf der Hibernate-Mapping-Konfiguration von Warenkorb wird der Schlüssel cart_id
für das Mapping verwendet.
Hibernate One To Many Mapping Beispiel – Testprogramm
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{
//Get Session
sessionFactory = HibernateUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
System.out.println("Session created");
//start transaction
tx = session.beginTransaction();
//Save the Model objects
session.save(cart);
session.save(item1);
session.save(item2);
//Commit 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();
}
}
}
}
Beachten Sie, dass wir sowohl Warenkorb- als auch Artikelobjekte einzeln speichern müssen. Hibernate kümmert sich um die Aktualisierung der Fremdschlüssel in der Artikeltabelle. Beim Ausführen des obigen Programms erhalten wir die folgende Ausgabe:
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
Beachten Sie, dass Hibernate ein Update-Query verwendet, um den cart_id
in der ITEMS
-Tabelle zu setzen.
Hibernate One To Many Mapping Annotation
Jetzt, da wir gesehen haben, wie One To Many Mapping in Hibernate mit XML-basierten Konfigurationen implementiert wird, sehen wir uns an, wie dasselbe mithilfe von JPA-Annotationen erreicht werden kann.
Hibernate One To Many Mapping Beispiel – Annotation
Die Hibernate-Konfigurationsdatei bleibt fast gleich, mit der Ausnahme, dass sich das Mapping-Element ändert, da wir Klassen für das Hibernate One To Many Mapping mithilfe von Annotationen verwenden.
hibernate-annotation.cfg.xml
com.mysql.jdbc.Driver
pankaj123
jdbc:mysql://localhost/TestDB
pankaj
org.hibernate.dialect.MySQLDialect
thread
true
Hibernate SessionFactory Utility-Klasse
Die Utility-Klasse für SessionFactory bleibt fast gleich. Wir müssen lediglich die neue Hibernate-Konfigurationsdatei verwenden.
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 {
// Create the SessionFactory from 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;
}
}
Hibernate One To Many Mapping Annotation Modellklassen
Da wir keine XML-basierten Mapping-Dateien haben, werden alle Mapping-bezogenen Konfigurationen mit JPA-Annotationen in den Modellklassen vorgenommen. Wenn Sie das XML-basierte Mapping verstanden haben, ist dies sehr einfach und ähnlich.
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;
// Getter Setter methods for properties
}
Ein wichtiger Punkt ist die OneToMany
-Annotation, bei der die Variable mappedBy
verwendet wird, um die Eigenschaft in der Items1
-Klasse zu definieren, die für das Mapping verwendet wird.
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 requires no-args constructor
public Items1(){}
public Items1(String itemId, double total, int qty, Cart1 c){
this.itemId=itemId;
this.itemTotal=total;
this.quantity=qty;
this.cart1=c;
}
//Getter Setter methods
}
Hibernate One To Many Mapping Annotation Beispiel – Testprogramm
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{
//Get Session
sessionFactory = HibernateAnnotationUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
System.out.println("Session created");
//start transaction
tx = session.beginTransaction();
//Save the Model object
session.save(cart);
session.save(item1);
session.save(item2);
//Commit 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();
}
}
}
}
Ausgabe des Testprogramms
Wenn wir das obige Hibernate-Testprogramm ausführen, erhalten wir folgende Ausgabe:
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
Fazit
In diesem Tutorial haben wir Hibernate’s One To Many Mapping mithilfe von XML- und Annotationen-Konfigurationen untersucht.
Wir haben demonstriert, wie man Datenbanktabellen erstellt, sie mit Java-Klassen abbildet und Testprogramme implementiert, um die Mappings zu überprüfen.
Beide Ansätze haben ihre Vorteile, und die Wahl hängt weitgehend vom Projektkontext ab. Die Verwendung von JPA-Annotationen ist in modernen Anwendungen häufiger, da sie einfacher und in Java-Klassen integriert ist.