A one-to-many relationship occurs when one entity is related to many occurrences in another entity.

“One-to-many” example

This is a one-to-many relationship table design, a STOCK table has many occurrences STOCK_DAILY_RECORD table.

one-to-many-relationship

Hibernate implementation

In Hibernate, “one” means an object, “many” means a Collection interface. This “one-to-many” 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
  • StockDailyRecord.java -> STOCK_DAILY_RECORD table

and two XML mapping files to describe the table relationship.

  • Stock.hbm.xml -> STOCK table
  • StockDailyRecord.hbm.xml -> STOCK_DAILY_RECORD table
Stock.java
public class Stock implements java.io.Serializable {
   ...
   private Set<StockDailyRecord> stockDailyRecords = 
                                             new HashSet<StockDailyRecord>();
 
   public Set<StockDailyRecord> getStockDailyRecords() {
	return this.stockDailyRecords;
   }
   ...
   public void setStockDailyRecords(Set<StockDailyRecord> stockDailyRecords) {
	this.stockDailyRecords = stockDailyRecords;
   }
}
StockDailyRecord.java
public class StockDailyRecord implements java.io.Serializable {
 
   private Stock stock;
   ...
   public Stock getStock() {
	return this.stock;
   }
 
   public void setStock(Stock stock) {
	this.stock = stock;
   }
   ...
}
Stock.hbm.xml
<hibernate-mapping>
    <class name="com.mkyong.common.Stock" table="stock" ...>
      ....
      <set name="stockDailyRecords" inverse="true" table="stock_daily_record" ...>
          <key>
              <column name="STOCK_ID" not-null="true" />
          </key>
          <one-to-many class="com.mkyong.common.StockDailyRecord" />
      </set>
    </class>
</hibernate-mapping>

The inverse=”true” is tells Hibernate about the relationship owner is belong to other side , not the class. More detail….

StockDailyRecord.hbm.xml
<hibernate-mapping>
  <class name="com.mkyong.common.StockDailyRecord" table="stock_daily_record" ...>
      <many-to-one name="stock" class="com.mkyong.common.Stock" ...>
          <column name="STOCK_ID" not-null="true" />
      </many-to-one>
      ...
  </class>
</hibernate-mapping>

2. Hibernate annotation

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

  • Stock.java -> STOCK table
  • StockDailyRecord.java -> STOCK_DAILY_RECORD 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 Set<StockDailyRecord> stockDailyRecords = 
                                              new HashSet<StockDailyRecord>(0);
 
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "stock")
    public Set<StockDailyRecord> getStockDailyRecords() {
	return this.stockDailyRecords;
    }
 
    public void setStockDailyRecords(Set<StockDailyRecord> stockDailyRecords) {
	this.stockDailyRecords = stockDailyRecords;
    }
    ...

The “mappedBy” annotation is equal to inverse=”true” in XML mapping file.

StockDailyRecord.java
...
@Entity
@Table(name = "stock_daily_record", catalog = "mkyong", 
uniqueConstraints = @UniqueConstraint(columnNames = "DATE"))
public class StockDailyRecord implements java.io.Serializable {
        ...
	private Stock stock;
 
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "STOCK_ID", nullable = false)
	public Stock getStock() {
		return this.stock;
	}
 
	public void setStock(Stock stock) {
		this.stock = stock;
	}
        ...

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_DAILY_RECORD table.

        ...
        Session session = HibernateUtil.getSessionFactory().openSession();
        session.beginTransaction();
 
        Stock stock = new Stock();
        stock.setStockCode("4715");
        stock.setStockName("GENM");
 
        StockDailyRecord stockDailyRecords = new StockDailyRecord();
        stockDailyRecords.setPriceOpen(new Float("1.2"));
        stockDailyRecords.setPriceClose(new Float("1.1"));
        stockDailyRecords.setPriceChange(new Float("10.0"));
        stockDailyRecords.setVolume(2000000L);
        stockDailyRecords.setDate(new Date());
 
        stockDailyRecords.setStock(stock);        
        stock.getStockDailyRecords().add(stockDailyRecords);
 
        session.save(stockDailyRecords);
        session.save(stock);
 
        session.getTransaction().commit();
        ...

Saving the session.save(stockDailyRecords); is not necessary, you can enable the cascade option to save the stockDailyRecords automatically, read more about it…

Output
Hibernate: 
    insert 
    into
        mkyong.stock
        (STOCK_CODE, STOCK_NAME) 
    values
        (?, ?)
10:41:37,492 DEBUG StringType:133 - binding '4715' to parameter: 1
10:41:37,492 DEBUG StringType:133 - binding 'GENM' to parameter: 2
Hibernate: 
    insert 
    into
        mkyong.stock_daily_record
        (STOCK_ID, PRICE_OPEN, PRICE_CLOSE, PRICE_CHANGE, VOLUME, DATE) 
    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.