JPA OneToMany Unidirectional without Join Table

Posted on

In earlier post we had OneToMany uni-directional mapping with the help of JoinTable. In this post we will see how can we make it unidirectional without using JoinTable.
Let’s create our eclipse project and then add update our pom.xml.

pom.xml

<project
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://maven.apache.org/POM/4.0.0"
	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.hibernatesearch</groupId>
	<artifactId>MumzHibernateSearch</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>
	<name>MumzHibernateSearch</name>
	<url>http://maven.apache.org</url>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.hibernate.javax.persistence</groupId>
			<artifactId>hibernate-jpa-2.0-api</artifactId>
			<version>1.0.1.Final</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>4.1.7.Final</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>4.1.7.Final</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.21</version>
		</dependency>
	</dependencies>
</project>

Next we will write our Entity to model Book and BookShelf tables. BookShelf will contain a set of books. First we will write our MHSBookEntityBean.

MHSBookEntityBean.java

package com.mumz.test.hibernatesearch.entitybeans;

import java.io.Serializable;
import java.lang.Long;
import java.lang.String;
import javax.persistence.*;

/**
 * The Class MHSBookEntityBean.
 * @author prabhat.jha
 */
@Entity
@Table(name = "BOOK")
public class MHSBookEntityBean implements Serializable {

	/** The Constant serialVersionUID. */
	private static final long	serialVersionUID	= -5129783468137830152L;

	/** The id. */
	private Long				id					= null;

	/** The name. */
	private String				name				= null;

	/** The author. */
	private String				author				= null;

	/**
	 * Instantiates a new mHS book entity bean.
	 */
	public MHSBookEntityBean() {
		super();
	}

	/**
	 * Gets the id.
	 *
	 * @return the id
	 */
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "BOOK_ID")
	public Long getId() {
		return this.id;
	}

	/**
	 * Sets the id.
	 *
	 * @param id
	 *            the new id
	 */
	public void setId(Long id) {
		this.id = id;
	}

	/**
	 * Gets the name.
	 *
	 * @return the name
	 */
	@Column(name = "BOOK_NAME")
	public String getName() {
		return this.name;
	}

	/**
	 * Sets the name.
	 *
	 * @param name
	 *            the new name
	 */
	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 new author
	 */
	public void setAuthor(String author) {
		this.author = author;
	}

	/** (non-Javadoc)
	 * @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)
	 * @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 MHSBookEntityBean)) {
			return false;
		}
		MHSBookEntityBean other = (MHSBookEntityBean) 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)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "MHSBookEntityBean [id=" + id + ", name=" + name + ", author=" + author + "]";
	}
}

Next we will write our MHSBookShelfEntityBean

MHSBookShelfEntityBean.java

package com.mumz.test.hibernatesearch.entitybeans;

import java.io.Serializable;
import java.lang.Long;
import java.lang.String;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.*;

/**
 * The Class MHSBookShelfEntityBean.
 * 
 * @author prabhat.jha
 */
@Entity
@Table(name = "BOOK_SHELF")
public class MHSBookShelfEntityBean implements Serializable {
	
	/** The Constant serialVersionUID. */
	private static final long		serialVersionUID	= -7127365575633206221L;
	
	/** The id. */
	private Long					id;
	
	/** The name. */
	private String					name;
	
	/** The books. */
	private Set<MHSBookEntityBean>	books				= new HashSet<MHSBookEntityBean>();
	
	/**
	 * Instantiates a new mHS book shelf entity bean.
	 */
	public MHSBookShelfEntityBean() {
		super();
	}
	
	/**
	 * Gets the id.
	 * 
	 * @return the id
	 */
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "BOOK_SHELF_ID")
	public Long getId() {
		return this.id;
	}
	
	/**
	 * Sets the id.
	 * 
	 * @param id
	 *            the new id
	 */
	public void setId(Long id) {
		this.id = id;
	}
	
	/**
	 * Gets the name.
	 * 
	 * @return the name
	 */
	@Column(name = "BOOK_SHELF_NAME")
	public String getName() {
		return this.name;
	}
	
	/**
	 * Sets the name.
	 * 
	 * @param name
	 *            the new name
	 */
	public void setName(String name) {
		this.name = name;
	}
	
	/**
	 * Gets the books.
	 * 
	 * @return the books
	 */
	@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@JoinColumn(name = "BOOK_SHELF_ID", referencedColumnName = "BOOK_SHELF_ID")
	public Set<MHSBookEntityBean> getBooks() {
		return books;
	}
	
	/**
	 * Sets the books.
	 * 
	 * @param books
	 *            the new books
	 */
	public void setBooks(Set<MHSBookEntityBean> books) {
		this.books = books;
	}
	
	/**
	 * (non-Javadoc)
	 * 
	 * @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)
	 * 
	 * @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 MHSBookShelfEntityBean)) {
			return false;
		}
		MHSBookShelfEntityBean other = (MHSBookShelfEntityBean) 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)
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "MHSBookShelfEntityBean [id=" + id + ", name=" + name + ", books=" + books + "]";
	}
}

Highlighted code above shows removal of JoinTable (name is the name of the column in BOOK table and referencedColumnName is the name of column in BOOK_SHELF table).

Finally our persistence.xml and some test code to check our model.
persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" >
    <persistence-unit name="MumzJPA" transaction-type="RESOURCE_LOCAL">
    	<class>com.mumz.test.hibernatesearch.entitybeans.MHSBookEntityBean</class>
    	<class>com.mumz.test.hibernatesearch.entitybeans.MHSBookShelfEntityBean</class>
        <properties>
            <property name="hibernate.show_sql" value="true"/>
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
            <property name="hibernate.connection.password" value="root"/>
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost/jpa_schema"/>
            <property name="hibernate.connection.username" value="root"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
        </properties>
    </persistence-unit>
</persistence>

TestOneToManyJoinTable.java

package com.mumz.test.hibernatesearch.entitybeans;

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

import javax.persistence.EntityManager;
import javax.persistence.Persistence;

/**
 * The Class TestOneToManyJoinTable.
 * @author prabhat.jha
 */
public class TestOneToManyJoinTable {

	/**
	 * The main method.
	 *
	 * @param args
	 *            the arguments
	 */
	public static void main(String[] args) {
		EntityManager entityManager = Persistence.createEntityManagerFactory("MumzJPA").createEntityManager();
		try {
			Set<MHSBookEntityBean> books = new HashSet<MHSBookEntityBean>();
			MHSBookEntityBean mhsBookEntityBean = new MHSBookEntityBean();
			mhsBookEntityBean.setName("Java EE Pocket Guide");
			mhsBookEntityBean.setAuthor("Arun Gupta");
			books.add(mhsBookEntityBean);
			mhsBookEntityBean = new MHSBookEntityBean();
			mhsBookEntityBean.setName("Pro Android 4");
			mhsBookEntityBean.setAuthor("Satya Komatineni and Dave MacLean");
			books.add(mhsBookEntityBean);

			MHSBookShelfEntityBean bookShelfEntityBean = new MHSBookShelfEntityBean();
			bookShelfEntityBean.setName("Technical Books");
			bookShelfEntityBean.setBooks(books);

			entityManager.getTransaction().begin();
			entityManager.persist(bookShelfEntityBean);
			entityManager.getTransaction().commit();
		} catch (Exception e) {
			e.printStackTrace();
			entityManager.getTransaction().rollback();
		} finally {
			if (entityManager != null) {
				entityManager.close();
			}
			entityManager = null;
		}
	}
}

Database schema used for this code.

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';

DROP SCHEMA IF EXISTS `jpa_schema` ;
CREATE SCHEMA IF NOT EXISTS `jpa_schema` DEFAULT CHARACTER SET utf8 ;
USE `jpa_schema` ;

-- -----------------------------------------------------
-- Table `jpa_schema`.`book_shelf`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `jpa_schema`.`book_shelf` ;

CREATE  TABLE IF NOT EXISTS `jpa_schema`.`book_shelf` (
  `BOOK_SHELF_ID` INT(11) NOT NULL AUTO_INCREMENT ,
  `BOOK_SHELF_NAME` VARCHAR(45) NULL DEFAULT NULL ,
  PRIMARY KEY (`BOOK_SHELF_ID`) )
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;

-- -----------------------------------------------------
-- Table `jpa_schema`.`book`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `jpa_schema`.`book` ;

CREATE  TABLE IF NOT EXISTS `jpa_schema`.`book` (
  `BOOK_ID` INT(11) NOT NULL AUTO_INCREMENT ,
  `BOOK_AUTHOR` VARCHAR(45) NOT NULL ,
  `BOOK_NAME` VARCHAR(45) NOT NULL ,
  `BOOK_SHELF_ID` INT(11) NULL DEFAULT NULL ,
  PRIMARY KEY (`BOOK_ID`) ,
  INDEX `FK_BOOK_SHELF_ID` (`BOOK_SHELF_ID` ASC) ,
  CONSTRAINT `FK_BOOK_SHELF_ID`
    FOREIGN KEY (`BOOK_SHELF_ID` )
    REFERENCES `jpa_schema`.`book_shelf` (`BOOK_SHELF_ID` )
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = utf8;

SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

5 thoughts on “JPA OneToMany Unidirectional without Join Table

    Archie said:
    April 2, 2013 at 6:21 PM

    I’m brand new to this whole running a blog thing and
    placing feedback for back links. I see tons of people are just
    putting in comments like “outstanding article” or “great post”.
    Isn’t this spammy? How come so many blog sites allow this stuff to
    be published?

    jayendra said:
    February 13, 2015 at 1:25 AM

    i think its book_id instead of book_shelf_id in referenced column name : @JoinColumn(name = “BOOK_SHELF_ID”, referencedColumnName = “BOOK_SHELF_ID”)

      Alex said:
      April 8, 2015 at 11:16 PM

      agree

    Andrea said:
    April 23, 2015 at 12:13 AM

    Did someone try this and work?
    Thanks!

    Levi said:
    June 11, 2015 at 9:44 AM

    Fine way of explaining, and nice post to obtain facts
    on the topic of my presentation topic, which i am going
    to deliver in school.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s