Thursday, October 6, 2011

Persisting Entities with Parent Child relationship using JPA


There is an Entity Class Parent, Class Parent might have children of type Child. Parent has an id column and child as well of its own. Parent has its own Contact  information.

It is common to have Entity relationship of this kind. Is there a way to persist this relation using JPA without link tables?

Yes, this is possible. This is a standard bi-directional ManyToOne/OneToMany relationship. I have used the Oracle Toplink JPA implementation.

To make it precise and to the point I made this example simple with simple six steps

1. Setup your database and make sure the connection is successful with right parameters over the network.
I used
-          NetBeans IDE 6.9.1
-          Java DB with derby driver


1.      2. Created tables Parent [id, pname], Child [pid, cname] and Contact [pid, address]

2.      3. Setup a project in your IDE, use Java 5 and included derbyclient.jar and toplink-essentials.jar to the list of dependency libraries

3.     4. Create Entity classes as follows

package jpa;

import java.io.Serializable;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;

/**
  * @author Nageswara Rao V
  */

@Entity
public class Parent implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private String id;
    private String pname;

    @OneToMany(mappedBy="myparent", cascade=CascadeType.PERSIST)
    private List<Child> children;

    @OneToMany(mappedBy="myparent", cascade=CascadeType.PERSIST)
    private List<Contact> contacts;

    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getPname() {
        return this.pname;
    }
    public void setPname(String name) {
        this.pname = name;
    }
    public List<Contact> getContacts() {
        return contacts;
    }
    public void setContacts(List<Contact> contacts) {
        this.contacts = contacts;
    }
    public List<Child> getChildren() {
        return children;
    }
    public void setChildren(List<Child> children) {
        this.children = children;
    }
}



package jpa;

import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

/**
 * @author Nageswara Rao V
 */
@Entity
public class Contact implements Serializable {

    @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.PERSIST)
    @JoinColumn(name="pid", nullable=false)
    Parent myparent;

    @Id
    private String address;

    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public Parent getMyparent() {
        return myparent;
    }
    public void setMyparent(Parent myparent) {
        this.myparent = myparent;
    }
}

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package jpa;

import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

/**
 * @author Nageswara Rao V
 */
@Entity
public class Child implements Serializable {

    @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.PERSIST)
    @JoinColumn(name="pid", nullable=false)
    Parent myparent;

    @Id
    private String cname;

    public String getCname() {
        return cname;
    }
    public void setCname(String pname) {
        this.cname = pname;
    }
    public Parent getMyparent() {
        return myparent;
    }
    public void setMyparent(Parent myparent) {
        this.myparent = myparent;
    }
}




4.       5. Create META-INF/persistence.xml resource with the properties for database

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.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 persistence_1_0.xsd">
  <persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
    <provider>oracle.toplink.essentials.PersistenceProvider</provider>
    <class>jpa.Parent</class>
    <class>jpa.Child</class>
    <class>jpa.Contact</class>
    <properties>
      <property name="toplink.logging.level" value="FINEST"/>
      <property name="toplink.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
      <property name="toplink.jdbc.url" value="jdbc:derby://localhost:1527/sample"/>
      <property name="toplink.jdbc.user" value="app"/>
      <property name="toplink.jdbc.password" value="app"/>
    </properties>
  </persistence-unit>
</persistence>

5.       6. Create a test to persist entity relation and run it

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package jpa;

import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

/**
 * @author Nageswara Rao V
 */
public class TestParentChild {

    public static void main(String[] args) {

        EntityManagerFactory emf = Persistence.createEntityManagerFactory("default", new java.util.HashMap());
        EntityManager entityManager = (EntityManager) emf.createEntityManager();
       
        // Don't forget to begin transaction as it involved multiple entities
        entityManager.getTransaction().begin();

        // Create parent entity
        Parent myparent = new Parent();
        myparent.setPname("rao");

        // Parent can have more than one address
        List<Contact> contacts = new ArrayList<Contact>();

        Contact chennai = new Contact();
        chennai.setAddress("chennai address");
        chennai.setMyparent(myparent);
        contacts.add(chennai);

        Contact hyd = new Contact();
        hyd.setAddress("Hyd address");
        hyd.setMyparent(myparent);
        contacts.add(hyd);

        // Associate contacts to parent
        myparent.setContacts(contacts);

        // More children to parent
        List<Child> children = new ArrayList<Child>();

        // Child one
        Child nish = new Child();
        nish.setCname("nishanth");
        nish.setMyparent(myparent);
        children.add(nish);

        // Child two
        Child sri = new Child();
        sri.setCname("Shri");
        sri.setMyparent(myparent);
        children.add(sri);

        // Associate parent with children
        myparent.setChildren(children);

        // That's it... persist
        entityManager.persist(myparent);

        // Commit the transaction
        entityManager.getTransaction().commit();
    }
}