Introduction
The example below is based on the application https://www.mkyong.com/hibernate/hibernate-one-to-many-relationship-example-annotation.
I modified it a little bit to show how to automatically save the "many" records when the "one" record is saved in a one-to-many relationship.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mkyong.common</groupId>
<artifactId>HibernateExample</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>HibernateExample</name>
<url>http://maven.apache.org</url>
<repositories>
<repository>
<id>JBoss repository</id>
<url>http://repository.jboss.org/nexus/content/groups/public/</url>
</repository>
</repositories>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<!-- 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>
<!-- logback logging framework-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>0.9.28</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>0.9.28</version>
</dependency>
</dependencies>
</project>
Database 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;
Domain classes
package com.mkyong.stock;
import static javax.persistence.GenerationType.IDENTITY;
import java.util.LinkedList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
@Entity
@Table(name = "stock", catalog = "workshop", uniqueConstraints = { @UniqueConstraint(columnNames = "STOCK_NAME"),
@UniqueConstraint(columnNames = "STOCK_CODE") })
public class Stock implements java.io.Serializable {
private Integer stockId;
private String stockCode;
private String stockName;
private List stockDailyRecords = new LinkedList();
public Stock() {
}
public Stock(String stockCode, String stockName) {
this.stockCode = stockCode;
this.stockName = stockName;
}
public Stock(String stockCode, String stockName, List stockDailyRecords) {
this.stockCode = stockCode;
this.stockName = stockName;
this.stockDailyRecords = stockDailyRecords;
}
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "STOCK_ID", unique = true, nullable = false)
public Integer getStockId() {
return this.stockId;
}
public void setStockId(Integer stockId) {
this.stockId = stockId;
}
@Column(name = "STOCK_CODE", unique = true, nullable = false, length = 10)
public String getStockCode() {
return this.stockCode;
}
public void setStockCode(String stockCode) {
this.stockCode = stockCode;
}
@Column(name = "STOCK_NAME", unique = true, nullable = false, length = 20)
public String getStockName() {
return this.stockName;
}
public void setStockName(String stockName) {
this.stockName = stockName;
}
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "stock")
public List getStockDailyRecords() {
return this.stockDailyRecords;
}
public void setStockDailyRecords(List stockDailyRecords) {
this.stockDailyRecords = stockDailyRecords;
}
}
package com.mkyong.stock;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;
@Entity
@Table(name = "stock_daily_record", catalog = "workshop", uniqueConstraints = @UniqueConstraint(columnNames = "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;
public StockDailyRecord() {
}
public StockDailyRecord(Stock stock, Date date) {
this.stock = stock;
this.date = date;
}
public StockDailyRecord(Stock stock, Float priceOpen, Float priceClose,
Float priceChange, Long volume, Date date) {
this.stock = stock;
this.priceOpen = priceOpen;
this.priceClose = priceClose;
this.priceChange = priceChange;
this.volume = volume;
this.date = date;
}
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "RECORD_ID", unique = true, nullable = false)
public Integer getRecordId() {
return this.recordId;
}
public void setRecordId(Integer recordId) {
this.recordId = recordId;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "STOCK_ID", nullable = false)
public Stock getStock() {
return this.stock;
}
public void setStock(Stock stock) {
this.stock = stock;
}
@Column(name = "PRICE_OPEN", precision = 6)
public Float getPriceOpen() {
return this.priceOpen;
}
public void setPriceOpen(Float priceOpen) {
this.priceOpen = priceOpen;
}
@Column(name = "PRICE_CLOSE", precision = 6)
public Float getPriceClose() {
return this.priceClose;
}
public void setPriceClose(Float priceClose) {
this.priceClose = priceClose;
}
@Column(name = "PRICE_CHANGE", precision = 6)
public Float getPriceChange() {
return this.priceChange;
}
public void setPriceChange(Float priceChange) {
this.priceChange = priceChange;
}
@Column(name = "VOLUME")
public Long getVolume() {
return this.volume;
}
public void setVolume(Long volume) {
this.volume = volume;
}
@Temporal(TemporalType.DATE)
@Column(name = "DATE", unique = true, nullable = false, length = 10)
public Date getDate() {
return this.date;
}
public void setDate(Date date) {
this.date = date;
}
}
Test program
package com.mkyong;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import org.hibernate.Session;
import com.mkyong.stock.Stock;
import com.mkyong.stock.StockDailyRecord;
import com.mkyong.util.HibernateUtil;
/**
* Note that this project is from
* https://www.mkyong.com/hibernate/hibernate-one-to-many-relationship-example-annotation/
*
* @author yxu
*
*/
public class AppList {
public static void main(String[] args) {
System.out.println("Hibernate one to many (Annotation)");
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Stock stock = new Stock();
stock.setStockCode("70523");
stock.setStockName("PADIN2");
// session.save(stock);
List stockDailyRecordsSet = new LinkedList();
for (int i = 0; i < 3; i++) {
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(2018, 5, 16 + i));
stockDailyRecords.setStock(stock);
stockDailyRecordsSet.add(stockDailyRecords);
}
stock.setStockDailyRecords(stockDailyRecordsSet);
session.save(stock);
session.getTransaction().commit();
System.out.println("Done");
}
}
Run AppList, you should see that it creates the stock and the 3 StockDailyRecord records in the database.
Note that I used List as the collection type in Stock for StockDailyRecord. You can also use Set.
Note that the annotation "@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "stock")"
in the class Stock is the most important in the setup. Without "casecade=CascadeType.ALL", the StockDailyRecord will not be saved into the database when the Stock is saved.
Both the tables STOCK and STOCK_DAILY_RECORD use the AUTO_INCREMENT ID as the primary key. And the Java annotation uses @GeneratedValue(strategy = IDENTITY). If a sequence is used to generate the ID, change the annotation to something like below:
@Id
@Column(name = "MY_ID")
@SequenceGenerator(name = "MY_SEQ", sequenceName = "MY_SEQ", allocationSize=1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="MY_SEQ")
public Integer getMyId() {
return this.myId;
}
Other classes and files
package com.mkyong.util;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
return new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void shutdown() {
// Close caches and connection pools
getSessionFactory().close();
}
}
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/workshop>/property>
>property name="hibernate.connection.username">workshop>/property>
>property name="hibernate.connection.password">za>/property>
>property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect>/property>
>property name="show_sql">true>/property>
>property name="format_sql">true>/property>
>mapping class="com.mkyong.stock.Stock" />
>mapping class="com.mkyong.stock.StockDailyRecord" />
>/session-factory>
>/hibernate-configuration>