JPA Part 3: Basic Relationships

  • If you think in independent of source and target sides, one of the two sides will have the join column. That side is called the owning side or the owner of the relationship. The side that does not have the join column is called the non-owning or inverse side. If they are not there, the values default from the perspective of the attribute on the owning side.
  • Physical annotations that define the mapping to the columns in the database are always defined on the owning side of the relationship.
  • @ManyToOne mappings are always on the owning side of a relationship, so if there is a @JoinColumn, it should be found on the Many sides.
  • @OneToMany is practically always bidirectional. Therefore, mappedBy must be specified, that is the inverse. Another side is @ManyToOne that is the owning side.
  • @OneToOne, logically either side can be an owning sides. But you cannot avoid the ownership. Therefore, @mappedBy element is added to the inverse side (which is you decided) to indicate that the other side is the owning side.
  • @ManyToMany, there is no owning and inverse sides, but we have to define; otherwise it will be treated as unidirectional instead of bidirectional. We use the link table to resolve the problem of the many vs many,

image

Fig 1: HR Schema

As shown in the above Schema, Employee many to one department, as well as the Department has one-to-many Employees. Again, Employee has one to one Asset as well as Asset has one to one relationship with Employee. The relationship between the Employee entity and the Work is many to many. This has been simplified with the emp_work link table. In addition to that, there is id_gen table that is for the primary key generator using table strategy.

jpa_part3_sd

Fig 2: JPA Domain Model for HR Schema

The above diagram clearly shows the bidirectional relationships with roles and cardinalities.

Here the Employee Entity

package au.com.ojitha.blogspot.jpaex1.domain;  
  
import java.util.Collection;  
  
import javax.persistence.CascadeType;  
import javax.persistence.Column;  
import javax.persistence.Embedded;  
import javax.persistence.Entity;  
import javax.persistence.GeneratedValue;  
import javax.persistence.Id;  
import javax.persistence.JoinColumn;  
import javax.persistence.JoinTable;  
import javax.persistence.ManyToMany;  
import javax.persistence.ManyToOne;  
import javax.persistence.OneToOne;  
import javax.persistence.TableGenerator;  
  
/\*\*  
 \*  
 \* @author Ojitha  
 \*/  
@Entity  
public class Employee extends Person{  
    @Id  
    @TableGenerator(name = "empId\_Gen",   
        table = "ID\_GEN",   
        pkColumnName = "ID\_NAME",   
        valueColumnName = "LAST\_VAL",   
        initialValue = 0,  
        allocationSize=1)  
    @GeneratedValue(generator="empId\_Gen")  
    @Column(name = "EMP\_ID")  
    private int empId;  
  
    @Embedded  
    private Contact contact;  
      
    @ManyToOne(cascade={CascadeType.PERSIST})  
    @JoinColumn(name="DEPT\_ID")  
    private Department department;  
      
    @OneToOne(cascade={CascadeType.PERSIST})  
    @JoinColumn(name="ASSET\_NO")  
    private Asset asset;  
      
    @ManyToMany(cascade={CascadeType.PERSIST})  
    @JoinTable(name="EMP\_WORK",   
        joinColumns=@JoinColumn(name="LINK\_EMP\_ID"),  
        inverseJoinColumns=@JoinColumn(name="LINK\_WORK\_ID" )    )  
    private Collection<Work> works;  
      
    public int getEmpId() {  
        return empId;  
    }  
  
    public void setEmpId(int empId) {  
        this.empId = empId;  
    }  
  
    public Contact getContact() {  
        return contact;  
    }  
  
    public void setContact(Contact contact) {  
        this.contact = contact;  
    }  
  
    public Department getDepartment() {  
        return department;  
    }  
  
    public void setDepartment(Department department) {  
        this.department = department;  
    }  
  
    public Asset getAsset() {  
        return asset;  
    }  
  
    public void setAsset(Asset asset) {  
        this.asset = asset;  
    }  
  
    public Collection<Work> getWorks() {  
        return works;  
    }  
  
    public void setWorks(Collection<Work> works) {  
        this.works = works;  
    }  
  
}  

Hear the Department Entity

package au.com.ojitha.blogspot.jpaex1.domain;  
  
import java.util.Collection;  
  
import javax.persistence.Column;  
import javax.persistence.Entity;  
import javax.persistence.GeneratedValue;  
import javax.persistence.Id;  
import javax.persistence.OneToMany;  
import javax.persistence.Table;  
import javax.persistence.TableGenerator;  
  
@Entity  
@Table(name = "DEPT")  
public class Department {  
    @Id  
    @TableGenerator(name = "deptId\_Gen",   
        table = "ID\_GEN",   
        pkColumnName = "ID\_NAME",   
        valueColumnName = "LAST\_VAL",   
        initialValue = 0,  
        allocationSize=1)  
    @GeneratedValue(generator="deptId\_Gen")  
    @Column(name = "DEPT\_ID")  
    private int deptId;  
  
    @Column(name = "DEPT\_NAME")  
    private String name;  
  
    @OneToMany(mappedBy="department")  
    private Collection<Employee> employees;  
      
    public int getDeptId() {  
        return deptId;  
    }  
  
    public void setDeptId(int deptId) {  
        this.deptId = deptId;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public Collection<Employee> getEmployees() {  
        return employees;  
    }  
  
    public void setEmployees(Collection<Employee> employees) {  
        this.employees = employees;  
    }  
  
}  

Hear the Work entity

package au.com.ojitha.blogspot.jpaex1.domain;  
  
import java.util.Collection;  
import java.util.Date;  
  
import javax.persistence.CascadeType;  
import javax.persistence.Column;  
import javax.persistence.Entity;  
import javax.persistence.GeneratedValue;  
import javax.persistence.Id;  
import javax.persistence.ManyToMany;  
import javax.persistence.TableGenerator;  
import javax.persistence.Temporal;  
import javax.persistence.TemporalType;  
  
@Entity  
public class Work {  
  
    @Id  
    @TableGenerator(name = "workId\_Gen",   
        table = "ID\_GEN",   
        pkColumnName = "ID\_NAME",   
        valueColumnName = "LAST\_VAL",   
        initialValue = 0,  
        allocationSize=1,  
        pkColumnValue="WORK\_ID")  
    @GeneratedValue(generator="workId\_Gen")  
    @Column(name="WORK\_ID")  
    private int workId;  
      
    @Column(name="DESCRIPTION")  
    private String description;  
      
    @Temporal(TemporalType.TIMESTAMP)  
    private Date startDate;  
      
    @ManyToMany(cascade={CascadeType.PERSIST},mappedBy="works")  
    private Collection<Employee> employees;  
  
    public int getWorkId() {  
        return workId;  
    }  
  
    public void setWorkId(int workId) {  
        this.workId = workId;  
    }  
  
    public String getDescription() {  
        return description;  
    }  
  
    public void setDescription(String description) {  
        this.description = description;  
    }  
  
    public Date getStartDate() {  
        return startDate;  
    }  
  
    public void setStartDate(Date startDate) {  
        this.startDate = startDate;  
    }  
  
    public Collection<Employee> getEmployees() {  
        return employees;  
    }  
  
    public void setEmployees(Collection<Employee> employees) {  
        this.employees = employees;  
    }  
      
}

Person, Contact, Address and State Enums already explained in the Part 1 of this series.

You can download the source from the GitHub.

Written with StackEdit.

Comments

Popular posts from this blog

How To: GitHub projects in Spring Tool Suite

Spring 3 Part 7: Spring with Databases

Parse the namespace based XML using Python