A one-to-one relationships occurs when one entity is related to exactly one occurrence in another entity.

“One-to-one” example

This is a one-to-one relationship table design, a STOCK table contains exactly one record in STOCK_DETAIL table. Both tables have the same Stock_Id as primary key. In STOCK_DETAIL table, Stock_Id is the primary key and also a foreign key to STOCK table. This is one of the common ways to define one-to-one relationship. More detail…

one-to-one-relationship

Hibernate implementation

In Hibernate, this “one-to-one” relationship can implemented in two ways :

  • Hibernate XML Mapping file
  • Hibernate Annotation

1. Hibernate XML mapping file

In XML mapping way, you need two Java classes to hold the table data.

  • Stock.java -> STOCK table
  • StockDetail.java -> STOCK_DETAIL table

and two XML mapping files to describe the table relationship.

  • Stock.hbm.xml -> STOCK table
  • StockDetail.hbm.xml -> STOCK_DETAIL table
Stock.java
...
public class Stock implements java.io.Serializable {
	private StockDetail stockDetail;
	...
	public StockDetail getStockDetail() {
		return this.stockDetail;
	}
	public void setStockDetail(StockDetail stockDetail) {
		this.stockDetail = stockDetail;
	}
StockDetail.java
...
public class StockDetail implements java.io.Serializable {
	private Stock stock;
        ...
        public Stock getStock() {
		return this.stock;
	}
 
	public void setStock(Stock stock) {
		this.stock = stock;
	}
Stock.hbm.xml
...
<class name="com.mkyong.common.Stock" table="stock" ...>
        <id name="stockId" type="java.lang.Integer">
            <column name="STOCK_ID" />
            <generator class="identity" />
        </id>
        ...
        <one-to-one name="stockDetail" class="com.mkyong.common.StockDetail" 
         cascade="save-update"></one-to-one>
        ...
StockDetail.hbm.xml
...
<class name="com.mkyong.common.StockDetail" table="stock_detail" ...>
        <id name="stockId" type="java.lang.Integer">
            <column name="STOCK_ID" />
            <generator class="foreign">
                <param name="property">stock</param>
            </generator>
        </id>
        <one-to-one name="stock" class="com.mkyong.common.Stock" 
        constrained="true"></one-to-one>
        ...

The main difficulty with one-to-one relationship is ensuring both are assigned the same primary key. In StockDetail.hbm.xml, a special foreign identifier generator is declared, it will know get the primary key value from STOCK table. With constrained=”true”, it ensure the Stock must exists.

2. Hibernate annotation

In annotation way, only two classes are required, all the relationships are declared inside the Java classes.

  • Stock.java -> STOCK table
  • StockDetail.java -> STOCK_DETAIL table
Stock.java
...
@Entity
@Table(name = "stock", catalog = "mkyong", uniqueConstraints = {
		@UniqueConstraint(columnNames = "STOCK_NAME"),
		@UniqueConstraint(columnNames = "STOCK_CODE") })
public class Stock implements java.io.Serializable {
	private StockDetail stockDetail;
        ...
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "STOCK_ID", unique = true, nullable = false)
	public Integer getStockId() {
		return this.stockId;
	}
 
	@OneToOne(fetch = FetchType.LAZY, mappedBy = "stock")
	@Cascade({CascadeType.SAVE_UPDATE})
	public StockDetail getStockDetail() {
		return this.stockDetail;
	}
StockDetail.java
@Entity
@Table(name = "stock_detail", catalog = "mkyong")
public class StockDetail implements java.io.Serializable {
	private Stock stock;
        ...
	@GenericGenerator(name = "generator", 
            strategy = "foreign", 
            parameters = @Parameter(name = "property", value = "stock"))
	@Id
	@GeneratedValue(generator = "generator")
	@Column(name = "STOCK_ID", unique = true, nullable = false)
	public Integer getStockId() {
		return this.stockId;
	}
 
	@OneToOne(fetch = FetchType.LAZY)
	@PrimaryKeyJoinColumn
	public Stock getStock() {
		return this.stock;
	}

The code is self-explanatory, all the @annotation are the XML mapping tag substitution.

Test It

Run the example, both annotation and XML mapping file will generate the same output. Hibernate inserts a row into the STOCK table and a row into the STOCK_DETAIL table.

        Stock stock = new Stock();
 
        stock.setStockCode("4715");
        stock.setStockName("GENM");
 
        StockDetail stockDetail = new StockDetail();
        stockDetail.setCompName("GENTING Malaysia");
        stockDetail.setCompDesc("Best resort in the world");
        stockDetail.setListedDate(new Date());
 
        stock.setStockDetail(stockDetail);
        stockDetail.setStock(stock);
 
        session.save(stock);
Output
Hibernate: 
    INSERT INTO mkyong.stock
    (STOCK_CODE, STOCK_NAME) 
    VALUES (?, ?)
 
Hibernate: 
    INSERT INTO mkyong.stock_detail
    (COMP_NAME, COMP_DESC, REMARK, LISTED_DATE, STOCK_ID) 
    VALUES (?, ?, ?, ?, ?)

Download Full Project

In this tutorial, many files and configuration steps are hidden, only the important files are remark. If you are interest to do the hand-on, you can download the full project here.

These two projects are developed in Eclipse IDE, using Maven as project management tool, and MySQL as database engine. The MySQL table creation scripts are stored in “db” folder.

This article was posted in Hibernate category.

Related Posts