OneToMany as name suggest is the scenario where one entity can be linked to multiple entities.
For e.g. one BookShelf can contain multiple books. In this tutorial we will use the same problem statement and model it using JPA with Hibernate as the JPA implementation provider.
First we will write our simple BookShelf
entity, BookShelf
will contain a List
of Books.
BookShelf.java
package com.mumz.jpa.mapping.onetomany; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; /** * The Class BookShelf. * @author prabhat.jha */ @Entity @Table(name = "BOOK_SHELF") public class BookShelf { /** The id. */ private Long id = null; /** The name. */ private String name = null; /** The books. */ private List<Book> books = null; /** * Gets the id. * * @return the id */ @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="BOOK_SHELF_ID") public Long getId() { return id; } /** * Sets the id. * * @param id * the id to set */ public void setId(Long id) { this.id = id; } /** * Gets the name. * * @return the name */ @Column(name="BOOK_SHELF_NAME") public String getName() { return name; } /** * Sets the name. * * @param name * the name to set */ public void setName(String name) { this.name = name; } /** * Gets the books. * * @return the books */ @OneToMany(cascade=CascadeType.ALL, mappedBy="bookShelf") public List<Book> getBooks() { return books; } /** * Sets the books. * * @param books * the books to set */ public void setBooks(List<Book> books) { this.books = books; } /** * (non-Javadoc). * * @return the int * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((books == null) ? 0 : books.hashCode()); result = prime * result + ((id == null) ? 0 : id.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } /** * (non-Javadoc). * * @param obj * the obj * @return true, if successful * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof BookShelf)) { return false; } BookShelf other = (BookShelf) obj; if (books == null) { if (other.books != null) { return false; } } else if (!books.equals(other.books)) { return false; } if (id == null) { if (other.id != null) { return false; } } else if (!id.equals(other.id)) { return false; } if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } return true; } /** * (non-Javadoc). * * @return the string * @see java.lang.Object#toString() */ @Override public String toString() { return String.format("BookShelf [id=%s, name=%s, books=%s]", id, name, books); } }
On line number 78 we have added @OneToMany annotation with :
- cacade=CascadeType.ALL – Suggests what to do with Books when BookShelf is deleted
- mappedBy – Name of the owner object
Second we will write our Book entity which is a simple entity with @ManyToOne
mapping.
Book.java
package com.mumz.jpa.mapping.onetomany; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; /** * The Class Book. * @author prabhat.jha */ @Entity @Table(name = "BOOK") public class Book implements Serializable{ /** The Constant serialVersionUID. */ private static final long serialVersionUID = -4788522141255171404L; /** The id. */ private Long id = null; /** The name. */ private String name = null; /** The author. */ private String author = null; /** The book shelf. */ private BookShelf bookShelf = null; /** * Gets the id. * * @return the id */ @Id @GeneratedValue(strategy=GenerationType.AUTO) @Column(name="BOOK_ID") public Long getId() { return id; } /** * Sets the id. * * @param id * the id to set */ public void setId(Long id) { this.id = id; } /** * Gets the name. * * @return the name */ @Column(name="BOOK_NAME") public String getName() { return name; } /** * Sets the name. * * @param name * the name to set */ public void setName(String name) { this.name = name; } /** * Gets the author. * * @return the author */ @Column(name="BOOK_AUTHOR") public String getAuthor() { return author; } /** * Sets the author. * * @param author * the author to set */ public void setAuthor(String author) { this.author = author; } /** * Gets the book shelf. * * @return the bookShelf */ @ManyToOne @JoinColumn(name="BOOK_SHELF_ID") public BookShelf getBookShelf() { return bookShelf; } /** * Sets the book shelf. * * @param bookShelf * the bookShelf to set */ public void setBookShelf(BookShelf bookShelf) { this.bookShelf = bookShelf; } /** * (non-Javadoc). * * @return the int * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((author == null) ? 0 : author.hashCode()); result = prime * result + ((id == null) ? 0 : id.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } /** * (non-Javadoc). * * @param obj * the obj * @return true, if successful * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof Book)) { return false; } Book other = (Book) obj; if (author == null) { if (other.author != null) { return false; } } else if (!author.equals(other.author)) { return false; } if (id == null) { if (other.id != null) { return false; } } else if (!id.equals(other.id)) { return false; } if (name == null) { if (other.name != null) { return false; } } else if (!name.equals(other.name)) { return false; } return true; } /** * (non-Javadoc). * * @return the string * @see java.lang.Object#toString() */ @Override public String toString() { return String.format("Book [id=%s, name=%s, author=%s]", id, name, author); } }
Third we will write a simple class to test out our application.
TestOneToMany
package com.mumz.jpa.mapping.onetomany; import java.util.ArrayList; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; /** * The Class TestOneToMany. * @author prabhat.jha */ public class TestOneToMany { /** * The main method. * * @param args * the arguments */ public static void main(String[] args) { EntityManager entityManager = Persistence.createEntityManagerFactory("jpaPersistenceUnit").createEntityManager(); BookShelf bookShelf = new BookShelf(); bookShelf.setName("JPA Books"); List<Book> books = new ArrayList<Book>(); Book book = new Book(); book.setName("Java Persistence with Hibernate"); book.setAuthor("Christian Bauer and Gavin King"); book.setBookShelf(bookShelf); books.add(book); book = new Book(); book.setName("Hibernate Made Easy"); book.setAuthor("Hibernate Made Easy"); book.setBookShelf(bookShelf); books.add(book); bookShelf.setBooks(books); EntityTransaction entityTransaction = entityManager.getTransaction(); try { entityTransaction.begin(); entityManager.persist(bookShelf); entityTransaction.commit(); } catch (Exception e) { e.printStackTrace(); entityTransaction.rollback(); } finally { entityManager.close(); } } }
Fourth our persistence.xml
which holds our mapped classes and database details.
persistence.xml
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> <persistence-unit name="jpaPersistenceUnit" transaction-type="RESOURCE_LOCAL"> <class>com.mumz.jpa.mapping.onetomany.BookShelf</class> <class>com.mumz.jpa.mapping.onetomany.Book</class> <properties> <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" /> <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpa_schema" /> <property name="javax.persistence.jdbc.user" value="root" /> <property name="javax.persistence.jdbc.password" value="root" /> </properties> </persistence-unit> </persistence>
Finally our pom.xml
to maintain our dependency.
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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mumz.test.jpa</groupId> <artifactId>TestJPAProject</artifactId> <version>0.0.1-SNAPSHOT</version> <name>TestJPAProject</name> <description>TestJPAProject</description> <dependencies> <dependency> <groupId>org.hibernate.javax.persistence</groupId> <artifactId>hibernate-jpa-2.0-api</artifactId> <version>1.0.0.Final</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </build> </project>