Hibernate – One-to-Many example (XML Mapping)

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

In this tutorial, we show you how to works with one-to-many table relationship in Hibernate, via XML mapping file (hbm).

Tools and technologies used in this tutorials :

  1. Hibernate 3.6.3.Final
  2. MySQL 5.1.15
  3. Maven 3.0.3
  4. Eclipse 3.6

Project Structure

Project structure of this tutorial.

one to many folder

Project Dependency

Get hibernate.jar from JBoss repository, Maven will take care all the related dependencies for you

File : pom.xml


<project ...>
 
	<repositories>
		<repository>
			<id>JBoss repository</id>
			<url>http://repository.jboss.org/nexus/content/groups/public/</url>
		</repository>
	</repositories>
 
	<dependencies>
 
		<!-- MySQL database driver -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.15</version>
		</dependency>
 
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>3.6.3.Final</version>
		</dependency>
 
		<dependency>
			<groupId>javassist</groupId>
			<artifactId>javassist</artifactId>
			<version>3.12.1.GA</version>
		</dependency>
 
	</dependencies>
</project>

1. “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 table relationship

See MySQL table scripts


DROP TABLE IF EXISTS `stock`;
CREATE TABLE `stock` (
  `STOCK_ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `STOCK_CODE` varchar(10) NOT NULL,
  `STOCK_NAME` varchar(20) NOT NULL,
  PRIMARY KEY (`STOCK_ID`) USING BTREE,
  UNIQUE KEY `UNI_STOCK_NAME` (`STOCK_NAME`),
  UNIQUE KEY `UNI_STOCK_ID` (`STOCK_CODE`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8;


DROP TABLE IF EXISTS `mkyongdb`.`stock_daily_record`;
CREATE TABLE  `mkyongdb`.`stock_daily_record` (
  `RECORD_ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `PRICE_OPEN` float(6,2) DEFAULT NULL,
  `PRICE_CLOSE` float(6,2) DEFAULT NULL,
  `PRICE_CHANGE` float(6,2) DEFAULT NULL,
  `VOLUME` bigint(20) unsigned DEFAULT NULL,
  `DATE` date NOT NULL,
  `STOCK_ID` int(10) unsigned NOT NULL,
  PRIMARY KEY (`RECORD_ID`) USING BTREE,
  UNIQUE KEY `UNI_STOCK_DAILY_DATE` (`DATE`),
  KEY `FK_STOCK_TRANSACTION_STOCK_ID` (`STOCK_ID`),
  CONSTRAINT `FK_STOCK_TRANSACTION_STOCK_ID` FOREIGN KEY (`STOCK_ID`) 
  REFERENCES `stock` (`STOCK_ID`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8;

2. Hibernate Model Class

Create two model classes – Stock.java and StockDailyRecord.java, to represent the above tables.

File : Stock.java


package com.mkyong.stock;

import java.util.HashSet;
import java.util.Set;

public class Stock implements java.io.Serializable {

	private Integer stockId;
	private String stockCode;
	private String stockName;
	private Set<StockDailyRecord> stockDailyRecords = 
				new HashSet<StockDailyRecord>(0);

	//getter, setter and constructor
}

File : StockDailyRecord.java


package com.mkyong.stock;

import java.util.Date;

public class StockDailyRecord implements java.io.Serializable {

	private Integer recordId;
	private Stock stock;
	private Float priceOpen;
	private Float priceClose;
	private Float priceChange;
	private Long volume;
	private Date date;

	//getter, setter and constructor
}

3. Hibernate XML Mapping

Now, create two Hibernate mapping files (hbm) – Stock.hbm.xml and StockDailyRecord.hbm.xml.

File : Stock.hbm.xml


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.mkyong.stock.Stock" table="stock" catalog="mkyongdb">
        <id name="stockId" type="java.lang.Integer">
            <column name="STOCK_ID" />
            <generator class="identity" />
        </id>
        <property name="stockCode" type="string">
            <column name="STOCK_CODE" length="10" not-null="true" unique="true" />
        </property>
        <property name="stockName" type="string">
            <column name="STOCK_NAME" length="20" not-null="true" unique="true" />
        </property>
        <set name="stockDailyRecords" table="stock_daily_record" 
				inverse="true" lazy="true" fetch="select">
            <key>
                <column name="STOCK_ID" not-null="true" />
            </key>
            <one-to-many class="com.mkyong.stock.StockDailyRecord" />
        </set>
    </class>
</hibernate-mapping>

File : StockDailyRecord.hbm.xml


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.mkyong.stock.StockDailyRecord" table="stock_daily_record" 
		catalog="mkyongdb">
        <id name="recordId" type="java.lang.Integer">
            <column name="RECORD_ID" />
            <generator class="identity" />
        </id>
        <many-to-one name="stock" class="com.mkyong.stock.Stock" fetch="select">
            <column name="STOCK_ID" not-null="true" />
        </many-to-one>
        <property name="priceOpen" type="java.lang.Float">
            <column name="PRICE_OPEN" precision="6" />
        </property>
        <property name="priceClose" type="java.lang.Float">
            <column name="PRICE_CLOSE" precision="6" />
        </property>
        <property name="priceChange" type="java.lang.Float">
            <column name="PRICE_CHANGE" precision="6" />
        </property>
        <property name="volume" type="java.lang.Long">
            <column name="VOLUME" />
        </property>
        <property name="date" type="date">
            <column name="DATE" length="10" not-null="true" unique="true" />
        </property>
    </class>
</hibernate-mapping>

4. Hibernate Configuration File

Puts Stock.hbm.xml and StockDailyRecord.hbm.xml in your Hibernate configuration file, and also MySQL connection details.

File : hibernate.cfg.xml


<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.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.url">jdbc:mysql://localhost:3306/mkyongdb</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">password</property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="show_sql">true</property>
    <property name="format_sql">true</property>
    <mapping resource="com/mkyong/stock/Stock.hbm.xml" />
    <mapping resource="com/mkyong/stock/StockDailyRecord.hbm.xml" />
</session-factory>
</hibernate-configuration>

5. Run It

Run it, Hibernate will insert a row into the STOCK table and a row into the STOCK_DAILY_RECORD table.

File : App.java


package com.mkyong;

import java.util.Date;

import org.hibernate.Session;

import com.mkyong.stock.Stock;
import com.mkyong.stock.StockDailyRecord;
import com.mkyong.util.HibernateUtil;

public class App {
	public static void main(String[] args) {
	
        System.out.println("Hibernate one to many (XML Mapping)");
	Session session = HibernateUtil.getSessionFactory().openSession();

	session.beginTransaction();

	Stock stock = new Stock();
        stock.setStockCode("7052");
        stock.setStockName("PADINI");
        session.save(stock);
        
        StockDailyRecord stockDailyRecords = new StockDailyRecord();
        stockDailyRecords.setPriceOpen(new Float("1.2"));
        stockDailyRecords.setPriceClose(new Float("1.1"));
        stockDailyRecords.setPriceChange(new Float("10.0"));
        stockDailyRecords.setVolume(3000000L);
        stockDailyRecords.setDate(new Date());
        
        stockDailyRecords.setStock(stock);        
        stock.getStockDailyRecords().add(stockDailyRecords);

        session.save(stockDailyRecords);

	session.getTransaction().commit();
	System.out.println("Done");
	}
}

Output …


Hibernate one to many (XML Mapping)
Hibernate: 
    insert 
    into
        mkyongdb.stock
        (STOCK_CODE, STOCK_NAME) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        mkyongdb.stock_daily_record
        (STOCK_ID, PRICE_OPEN, PRICE_CLOSE, PRICE_CHANGE, VOLUME, DATE) 
    values
        (?, ?, ?, ?, ?, ?)
Hibernate Annotation
For one-to-many in Hibernate annotation, please refer to this example.
Download it – Hibernate-one-to-many-xml-mapping.zip (10KB)

Reference

  1. Hibernate Documentation – one to many relationship.

About the Author

author image
mkyong
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter, or befriend him on Facebook or Google Plus. If you like my tutorials, consider make a donation to these charities.

Comments

avatar
42 Comment threads
15 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
42 Comment authors
Saurabhamit nihaljavalschoolKnagendiran NaguBinh Thanh Nguyen Recent comment authors
newest oldest most voted
amit nihal
Guest
amit nihal

Thanks Mkyong for great tutorial…but can you please let me know as how to write controller and jsp/jstl page for such object. i have tried many ways but unable to reach my destination. it will be great help if you share with code.

javalschool
Guest
javalschool

Nice article sir

Knagendiran Nagu
Guest
Knagendiran Nagu

Will you please give an example for one to many/many to one association on join table with xml mapping for this similar or different example

Binh Thanh Nguyen
Guest
Binh Thanh Nguyen

Thanks, nice post

Mithilesh92
Guest
Mithilesh92
vijay
Guest
vijay

Is it mandatory to use

session.getTransaction().commit();? Cant we just use session.save()

Saurabh
Guest
Saurabh

No, we cannot use save() only method because it will save the session objects to database or memory but changes will no reflect back until transaction(commit or rollback) is not called

Abhishek Oza
Guest
Abhishek Oza

Nice work. I must make a point though. The example can confuse a newbie whether the column name “STOCK_ID” mentioned in Stock.hbm.xml refers to the STOCK_ID in stock table, or the stock_daily_record table. Here is another example in hibernate many-to-one(xml mapping): http://www.tutorialspoint.com/hibernate/hibernate_one_to_many_mapping.htm . This example does not create any confusion.

Vander Fula
Guest
Vander Fula

very Helpfull.

Now what if i want to add more stock_daily_record with the same stock??

Az MaYo
Guest
Az MaYo

Best Example for clear image of One to Many …. :)

yashwanth
Guest
yashwanth

cascade=”all” with set worked for me.

Stock s = new Stock();
s.setStockCode(“1012”);
s.setStockName(“Hutch”); //single stock called “Hutch”

// Two stock prices for “Hutch” stock
StockPrice sp = new StockPrice();
StockPrice sp1 = new StockPrice();

sp.setDate(new Date());
sp.setPriceChange(745);
sp.setPriceClose(643);
sp.setPriceOpen(734);
sp.setVolume(134);

sp1.setDate(new Date());
sp1.setPriceChange(879);
sp1.setPriceClose(433);
sp1.setPriceOpen(124);
sp1.setVolume(86);

sp.setStock(s);
sp1.setStock(s);

Set spSet = new HashSet(); // Add stock price (StockDailyRecord) to the set

spSet.add(sp);
spSet.add(sp1);

s.setStockPrice(spSet); //setting the stock price set “spSet ” to Stock.setStockPrice()

sDao.saveStock(s);

Ali Bassam
Guest
Ali Bassam

In case I’m using Spring, should I inject Stock class in StockDailyRecord (Dependency Injection)?

Romil
Guest
Romil

Nice post and a rocking blog

David Newcomb
Guest
David Newcomb

Nice article but you’ve inadvertently made it confusing. STOCK_ID is the primary key for Stocks and STOCK_ID is the secondary key name in StockDailyRecord.
The result of this is that when you mention STOCK_ID in the mapping files, I don’t know which you are referring to. In my schema “id” is the primary key name and “person_id” is the secondary key name.

Any chance you could update the article with different columns names? Pretty please!?!

Francisco Castellano
Guest
Francisco Castellano

Hello mkyong,

It would be very usefull that the foreing column doesn’t have the same name that the primary column

Regards

IT and Non Jobs
Guest
IT and Non Jobs

Nice Article for One to Many Relationship. It is very useful for me. Thank you

Jim
Guest
Jim

Hi, I am getting this exception when i am using the above source code. Please help SEVERE: Cannot add or update a child row: a foreign key constraint fails (`new_db`.`stock_daily_record`, CONSTRAINT `FK_STOCK_TRANSACTION_STOCK_ID` FOREIGN KEY (`STOCK_ID`) REFERENCES `stock` (`STOCK_ID`) ON DELETE CASCADE ON UPDATE CASCADE) Mar 12, 2013 10:02:30 PM org.hibernate.event.def.AbstractFlushingEventListener performExecutions SEVERE: Could not synchronize database state with session org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71) at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43) at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:253) at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:266) at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167) at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298) at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27) at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000) at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338) at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106) at in.greensoft.dao.impl.test.DoctorHibernateTest.main(DoctorHibernateTest.java:44) Caused by: java.sql.BatchUpdateException: Cannot add or update a child row: a foreign… Read more »

Amit
Guest
Amit

getting following error while insert more than one record.
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update

hubek
Guest
hubek

nice tutorial, thx

Suman Kumar
Guest
Suman Kumar

Content and tutorial in this website is very helpfull and good. please add some tutorial on LINUX/UNIX , Shell scripting tutorial

Paul
Guest
Paul

In all of your examples you include a reference to the other object (Stock in this case) inside the other objects (such as StockItem). I completely understand why Stock would have a StockItem Object but why does each StockItem have a reference back to the stock object?

Please can you explain.

sagar
Guest
sagar

If I use cascade=”all” and call
session.save(stock);
then it should save data in both the table.
But getting child constrains exception.

But this work fine with Bag
Why cascade”all” doesn’t work with Set?

Vivek K
Guest
Vivek K

Hi,

Great article, thanks!

Alice Kinston
Guest
Alice Kinston

My husband and i ended up being absolutely joyful when Jordan managed to finish off his researching while using the precious recommendations he grabbed when using the blog. It’s not at all simplistic to just continually be handing out points that many others may have been trying to sell. We really fully understand we have the writer to give thanks to for that. The specific illustrations you’ve made, the simple website navigation, the relationships you can assist to create – it is mostly impressive, and it is helping our son in addition to us imagine that this issue is cool,… Read more »

anooj
Guest
anooj

plz tell me how to retrieve database inner-joined values to jsp page and list box . and how to save only id from the list box to database ?? plz tell me by considering the above example

shyamshyre
Guest
shyamshyre

Hi Mkyong,

I have a user table which consists of multiple roles.(Pointing to Roles Table)
(One user multiple Roles).
When i am saving the Record its inserting successfully.
But when i am trying to update the record,Its updating and
even deleting the record from the created Relation-table.(USER_ROLES)

USER TABLE

@OneToMany(fetch = FetchType.EAGER)
public Set getUserroles() {
return userroles;
}
public void setUserroles(Set userroles) {
this.userroles = userroles;
}

When i am trying to go with my mapby its throwing error AnnotationException and mappedBy reference an unknown target entity property: .

Please help me.

hjc
Guest
hjc

Hi mkyong, Nice article. I am a noob to hibernate. Your tutorials are very helpful in understanding the core concepts since examples are provided. Appreciate it. I had a question. If I try to run the above program for first time, the parameters are all inserted into stock and stock_daily_record tables correctly. However when I try to run this again, I get the exception below. I may be wrong, but I thought hibernate would detect if there was a duplicate insertion and not insert the values. Caused by: java.sql.SQLException: Duplicate key or integrity constraint violation message from server: “Duplicate entry… Read more »

Jaya
Guest
Jaya

In One to Many Example

why you have to specify (StockDailyRecord.hbm.xml)

I don’t understand , Please can you explain

Ayesha
Guest
Ayesha

can u give a similar example for many to many mapping?

Prateek
Guest
Prateek
very nice way to submit this article
Neliel
Guest
Neliel

Hi Mkyong, Can you help me with my mapping? I am in doubt on whats the best approach? I have an insurance table and user could change the rate plan associated with it. Table Insurance: id long; accountHolder varchar; ratePlanId int; -->Rate Plan Id is Foreign Key to the RatePlanTable Table RatePlan: ratePlanId int; ratePlanDesc varchar; discountRate double; I have a class structure like this: public class Insurance{ private long id; private String accountHolder; private int ratePlanId; } public class RatePlan{ private int ratePlanId; private String ratePlanDesc; private double discountRate; } Is my table-class hierarchy correct? or should I change… Read more »