アノテーションを使用したHibernateの一対多のマッピング例
今日は、HibernateにおけるOne To Many Mappingについて見ていきます。注釈とXML設定を使用したHibernateのOne To Many Mappingの例を見ていきます。
Hibernateにおける一対多のマッピング
簡単に言うと、一対多のマッピングとは、あるテーブルの1行が他のテーブルの複数の行にマッピングされることを意味します。例えば、カートシステムを考えてみましょう。商品のために別のテーブルが存在します。カートには複数の商品が入ることができるため、ここで一対多のマッピングが行われます。私たちは、Hibernateの一対多のマッピングの例として、カートと商品のシナリオを使用します。
ヒバネートにおける「一対多のマッピング」- データベースの設定
1対多のマッピングには、外部キー制約を使用することができます。以下に、CartテーブルとItemsテーブルのデータベーススクリプトを示します。Hibernateの1対多マッピングの例としてMySQLデータベースを使用しています。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;
以下は、カートとアイテムのテーブルのER図です。データベースの設定は完了していますので、次にHibernateの一対多のマッピング例プロジェクトの作成に進みましょう。まず最初に、XMLベースの設定を使用し、次にHibernateとJPAのアノテーションを使用して一対多のマッピングを実装します。
ハイバネイトの一対多のマッピングプロジェクトの構造
お気に入りのIDE、またはEclipseで簡単なMavenプロジェクトを作成し、最終的なプロジェクトの構造は以下の画像のようになります。
ヒベルネイトのMaven依存関係
私たちの最終的なpom.xmlファイルには、HibernateとMySQLドライバーの依存関係が含まれています。HibernateはJBossのログを使用し、それは自動的に推移的な依存関係として追加されます。
<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.scdev.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>
データベースのインストールに基づいて、最新のHibernateバージョン4.3.5.FinalとMySQLドライバーバージョンを使用していることに注意してください。
ネイティブな日本語で以下を言い換えると、次の通りです。
Hibernateの一対多のマッピングモデルクラス
テーブル Cart と Items のために、それらを反映するためのモデルクラスがあります。Cart.java
package com.scdev.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;
}
}
私はSet of Itemsを使用していますので、すべてのレコードがユニークです。Hibernateでは、一対多のマッピングにはListまたはArrayも使用することができます。Items.java
package com.scdev.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;
}
}
アイテムはカートに対して多対一の関係を持つため、カートオブジェクトにはコレクションを持つ必要はありません。
ヒベルネートのSessionFactoryユーティリティクラス
私たちは、HibernateのSessionFactoryを作成するためのユーティリティクラスであるHibernateUtil.javaを持っています。
package com.scdev.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;
}
}
ヒベルネートの設定XMLファイル
私たちのハイバネートの設定ファイルである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">scdev123</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost/TestDB</property>
<property name="hibernate.connection.username">scdev</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>
ネイティブな日本語で以下を言い換えると、ヒベルネートのワン・トゥ・メニーのマッピング例 – XML構成
ヒベルネートのワン・トゥ・メニーのマッピング例について、XML設定を示します。
このチュートリアルの最も重要な部分は、Hibernateでの1対多のマッピングにおいてCartクラスとItemsクラスのマッピング方法を見ていくことです。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.scdev.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>
重要な部分はセット要素とその中に含まれる一対多の要素です。注意してください、私たちは一対多のマッピングに使用されるキー(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.scdev.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>
アイテムからカートへの関係は1対多の関係であることに気づいてください。したがって、カートには1対多の要素を使用する必要があり、キーに関連付けられる列名を提供しています。したがって、CartのHibernateマッピング構成に基づいて、キーとしてcart_idが使用されます。XMLマッピングを使用したHibernate One To Many Mappingのプロジェクトが準備できましたので、テストプログラムを書いて正常に動作するかどうかを確認しましょう。
ネイティブ日本語で次の文を言い換えてください。1つだけのオプションが必要です:
HibernateのOneToManyマッピングの例-テストプログラム
HibernateOneToManyMain.javaを日本語で自然に言い換えると次のようになります: “HibernateOneToManyMain.java”
package com.scdev.hibernate.main;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.scdev.hibernate.model.Cart;
import com.scdev.hibernate.model.Items;
import com.scdev.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<Items> itemsSet = new HashSet<Items>();
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();
}
}
}
}
以下のプログラムを実行すると、CartオブジェクトとItemsオブジェクトを一つずつ保存する必要があることに注意してください。HibernateはItemsテーブルの外部キーの更新を自動的に処理します。プログラムを実行すると、以下の出力が得られます。
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
ヒバーネートは、ITEMSテーブルのcart_idを設定するためにUpdateクエリを使用していることに注意してください。
ネイティブの日本語で以下の文を一つ挙げて言い換えましょう:
ハイバネートの一対多のマッピングアノテーション
XMLベースの設定を使用してHibernateでOne To Manyマッピングを実装する方法を見てきましたので、次はJPAアノテーションを使用して同じことを行う方法を見てみましょう。
ヒバネートのOne To Manyマッピングの例(アノテーションを使用)
ワンオンワンのマッピングには、アノテーションを使用しているため、ハイバネイトの設定ファイルはほぼ同じですが、マッピング要素に変更があります。 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">scdev123</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost/TestDB</property>
<property name="hibernate.connection.username">scdev</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.scdev.hibernate.model.Cart1"/>
<mapping class="com.scdev.hibernate.model.Items1"/>
</session-factory>
</hibernate-configuration>
ネイティブな日本語で、以下を一つの選択肢で言い換えると:
Hibernateのセッションファクトリーユーティリティクラス
セッションファクトリのユーティリティクラスはほぼ同じですが、新しいHibernateの設定ファイルを使用する必要があります。 HibernateAnnotationUtil.java
package com.scdev.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の一対多のマッピング
XMLベースのマッピングファイルがないため、すべてのマッピング関連の設定はJPA注釈を使用してモデルクラスで行われます。XMLベースのマッピングが理解できれば、非常に簡単で似ています。Cart1.java
package com.scdev.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> items1;
// Getter Setter methods for properties
}
重要な点は、OneToManyアノテーションである。このアノテーションでは、マッピングの目的でItems1クラスで使用されるプロパティを定義するために、mappedBy変数が使用されます。したがって、Items1クラスには「cart1」というプロパティが必要です。すべてのgetter-setterメソッドも含めることを忘れないでください。Items1.java
package com.scdev.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
}
上記のクラスにおける最も重要なポイントは、Cart1クラスの変数におけるManyToOne注釈と、マッピングのための列名を指定するJoinColumn注釈です。これが、モデルクラスにアノテーションを使用してHibernateでの一対多のマッピングに関するすべてです。XMLベースの設定と比較すると、非常に似ていることがわかります。テストプログラムを書いて実行しましょう。
ネイティブの日本語で以下を言い換えてください。オプションは1つだけ必要です。
HibernateのOne To Manyマッピングのアノテーションの例をテストするプログラム
私たちのテストプログラムは、XMLベースの設定と同じようであり、Hibernateのセッションを取得し、モデルオブジェクトをデータベースに保存するための新しいクラスを使用しています。HibernateOneToManyAnnotationMain.java
package com.scdev.hibernate.main;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.scdev.hibernate.model.Cart1;
import com.scdev.hibernate.model.Items1;
import com.scdev.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<Items1> itemsSet = new HashSet<Items1>();
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();
}
}
}
}
上記のHibernateの一対多のマッピングアノテーションの例テストプログラムを実行すると、次の出力が得られます。
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
それで、Hibernateのone-to-manyマッピングについては以上です。以下のリンクからサンプルプロジェクトをダウンロードして、さらにいくつかの実験を行ってください。
ネイティブな日本語で以下の文章を一つのオプションで言い換えます:
HibernateのOneToManyマッピングプロジェクトをダウンロードします。