ネイティブな日本語で以下の内容を言い換えると、アノテーションによるHibernate One to Oneのマッピングの例があります。ヒベルネートのOne to Oneマッピングのアノテーションの例
今日はHibernateのOne to Oneマッピングを見ていきます。アノテーションとXML構成を使用したHibernateのOne to Oneマッピングの例を見ていきます。
ヒバネイトにおけるワン・トゥ・ワン・マッピング
ほとんどの場合、データベースのテーブルは互いに関連付けられています。関連付けにはさまざまな形式があります。一対一、一対多、多対多が広範なレベルで存在します。これらは、単方向と双方向のマッピングにさらに分けることができます。今日は、XML構成および注釈構成を使用したHibernate One to One Mappingの実装方法を見てみましょう。
ワン・トゥ・ワン・マッピングの例としての、Hibernate データベースのセットアップ
まず最初に、データベーステーブルには一対一のマッピングを設定する必要があります。この例では、トランザクションと顧客の2つのテーブルを作成します。これらのテーブルはいずれも一対一のマッピングを持ちます。トランザクションが主テーブルであり、顧客テーブルでは一対一のマッピングのために外部キーを使用します。このチュートリアルではMySQLのスクリプトを提供していますが、他のデータベースを使用している場合はスクリプトを適宜変更してください。
-- Create Transaction Table
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;
-- Create Customer table
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;
上記のテーブル間の一対一のマッピングに関するエンティティ関係図(ERD)は、以下の画像のようになります。私たちのデータベースの設定は完了していますので、次にHibernate One to Oneのサンプルプロジェクトに進みましょう。
ネイティブの日本語で以下を言い換えてください。選択肢は一つだけで結構です。
Hibernateの一対一のマッピングの例のプロジェクト構造
JavaのIDE、Eclipseを使用して、シンプルなMavenプロジェクトを作成します。最終的なプロジェクトの構造は以下の画像のようになります。まずはXMLベースのHibernate One to One Mappingの例を見てから、同じことをアノテーションを使用して実装します。
ヒバネイト メイヴン デペンデンシーズ
私たちの最終的なpom.xmlファイルは以下のようになります。
<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>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>
依存関係は、HibernateとMySQLのJavaドライバーにのみ必要です。Hibernateの最新バージョンである4.3.5.Finalと、MySQLデータベースサーバーバージョン(5.0.5)に基づいてMySQLのJavaドライバーを使用しています。Hibernate 4では、JBossのロギングが使用され、推移的な依存関係として自動的にインポートされます。プロジェクトのMavenの依存関係で確認することができます。Hibernateの古いバージョンを使用している場合は、slf4jの依存関係を追加する必要があるかもしれません。
モデルクラスのHibernate One to Oneマッピング
データベーステーブルを反映するためのHibernate One to Oneマッピングのモデルクラスは、以下のようになります。
package com.scdev.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.scdev.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;
}
}
XMLベースの構成を使用しているため、上記のモデルクラスはシンプルなPOJOクラスまたはJavaBeansであり、getter-setterメソッドを持っています。Hibernate APIにはTransactionというクラス名があるため、混乱を避けるためにTxnというクラス名を使用しています。
Hibernateの一対一のマッピングの設定
TxnとCustomerテーブルのヒベルネートの1対1マッピングの設定ファイルを作成しましょう。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.scdev.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.scdev.hibernate.model.Customer"
cascade="save-update" />
</class>
</hibernate-mapping>
上記で注目すべき重要なポイントは、customerプロパティのヒベルネートのone-to-one要素です。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.scdev.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.scdev.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>
ジェネレータークラス「foreign」は、ヒベルネートの外部キー実装に使用される重要な部分です。
ヒベルネートの設定ファイル
こちらはXMLベースのHibernateマッピング設定のためのHibernate設定ファイルであり、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="txn.hbm.xml"/>
<mapping resource="customer.hbm.xml"/>
</session-factory>
</hibernate-configuration>
ヒベルネートの設定ファイルは、データベースの接続プロパティとヒベルネートのマッピングリソースを持つシンプルなものです。
ネイティブ日本語で以下を言い換えます。オプションは1つのみです:
HibernateのSessionFactoryユーティリティ
以下はHibernateのSessionFactoryインスタンスを作成するためのユーティリティクラスです。
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;
}
}
それで、Hibernateの1対1マッピングのXMLベースの設定をテストするためのテストプログラムを書きましょう。
ネイティブな日本語で以下を言い換える(オプションは1つだけ必要):
ハイバネートの一対一のマッピングXML設定のテストプログラム
ハイバネートの一対一のマッピングの例のテストプログラムでは、最初に Txn オブジェクトを作成して保存します。データベースに保存されたら、生成された ID を使用して Txn オブジェクトを取得し、それを表示します。
package com.scdev.hibernate.main;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.scdev.hibernate.model.Customer;
import com.scdev.hibernate.model.Txn;
import com.scdev.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{
//Get Session
sessionFactory = HibernateUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
System.out.println("Session created");
//start transaction
tx = session.beginTransaction();
//Save the Model object
session.save(txn);
//Commit transaction
tx.commit();
System.out.println("Transaction ID="+txn.getId());
//Get Saved Trasaction Data
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{
//Get Session
sessionFactory = HibernateUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
//start transaction
tx = session.beginTransaction();
//Save the Model object
Txn txn = (Txn) session.get(Txn.class, id);
//Commit transaction
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("scdev@gmail.com");
cust.setName("Pankaj Kumar");
txn.setCustomer(cust);
cust.setTxn(txn);
return txn;
}
}
今、私たちはHibernateのテストプログラムで上記の1対1マッピングを実行すると、以下の出力が得られます。
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, scdev@gmail.com, Bangalore, India
Closing SessionFactory
ご覧の通り、問題なく動作しており、トランザクションIDを使用して両方のテーブルからデータを取得できています。データを取得するためにHibernateが内部で使用しているSQLを確認してみてください。それは両方のテーブルからデータを取得するためにジョインを使用しています。
ワンツーワンのマッピング注釈によるHibernateの1対1の関連付け
上記のセクションでは、Hibernateの1対1マッピングのためのXMLベースの設定方法を見てきましたが、今度はJPAとHibernateのアノテーションを使って同じことを実現する方法を見てみましょう。
ハイバネートの設定ファイル
ネイティブの日本語で以下を言い換えます。1つのオプションだけが必要です。
「ハイバネートアノテーション.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.Txn1"/>
<mapping class="com.scdev.hibernate.model.Customer1"/>
</session-factory>
</hibernate-configuration>
ハイバネートの設定はシンプルです。アノテーションを使用する2つのモデルクラス、Txn1とCustomer1も確認できます。
Hibernateの一対一マッピングのアノテーションの例のモデルクラス
1つずつのマッピング注釈の設定には、ハイバネートでは、モデルクラスが最も重要な部分です。さて、モデルクラスを見てみましょう。
package com.scdev.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();
}
//Getter-Setter methods, omitted for clarity
}
大部分の注釈はJava Persistence APIに由来している点に注意してください。これはHibernateがその実装を提供しているからです。ただし、カスケードに関しては、Hibernateの注釈であるorg.hibernate.annotations.Cascadeと列挙型であるorg.hibernate.annotations.CascadeTypeを使用する必要があります。
package com.scdev.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;
//Getter-Setter methods
}
idを生成する代わりに、@GenericGeneratorを使用する必要があることに注意してください。
ネイティブで日本語に言い換えると以下のようになります(一つのオプションのみ):
Hibernateのセッションファクトリーユーティリティクラス
Hibernateのマッピングを提供する方法に依存せず、SessionFactoryの作成は行われます。SessionFactoryを作成するためのユーティリティクラスは以下のようになります。
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;
}
}
ネイティブな日本語で以下を言い換えます。1つのオプションで構いません:
Hibernate One to Oneマッピングのアノテーション例に関するテストプログラム
私たちのヒベルネートのワンツーワンマッピングのアノテーション例には、シンプルなテストプログラムがあります。
package com.scdev.hibernate.main;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.scdev.hibernate.model.Customer1;
import com.scdev.hibernate.model.Txn1;
import com.scdev.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{
//Get Session
sessionFactory = HibernateAnnotationUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
System.out.println("Session created using annotations configuration");
//start transaction
tx = session.beginTransaction();
//Save the Model object
session.save(txn);
//Commit transaction
tx.commit();
System.out.println("Annotation Example. Transaction ID="+txn.getId());
//Get Saved Trasaction Data
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{
//Get Session
sessionFactory = HibernateAnnotationUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
//start transaction
tx = session.beginTransaction();
//Save the Model object
Txn1 txn = (Txn1) session.get(Txn1.class, id);
//Commit transaction
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("scdev@yahoo.com");
cust.setName("Pankaj Kr");
txn.setCustomer(cust);
cust.setTxn(txn);
return txn;
}
}
上記のプログラムを実行したときの出力スニペットです。
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, scdev@yahoo.com, San Jose, USA
Closing SessionFactory
出力がハイバネートの1対1のXMLベースの設定に似ていることに注目してください。ハイバネートの1対1マッピングの例は以上です。最終プロジェクトは以下のリンクからダウンロードできますので、試してみてさらに学んでください。
HibernateのOneToOneマッピングプロジェクトをダウンロードしてください。