How to map a JSON hierarchy with JPA and Hibernate


#1

I have three entities:

  • user
  • division and
  • subdivision.

User is associated with division then subdivision associated with user and division.

How do I map this?

[
  username: x,
  division: [
       {
       divisionName: y,
       subdivision: [
            {
                 subdivisionname: z
            }
       ]
       }
 ]
]

#2

If you want to save it as-is, you can use a JSON column and use the hibernate-types project.

For more details, check out this article.

If you want to map those entities to 3 database tables, then you need to have:

  • a @ManyToOne association in User that references the Division
  • a @ManyToOne association to Division in SubDivision
  • Possible a bidirectional, mappedBy @OneToMany association in Division containing a List<SubDivision> and a bidirectional, mappedBy @OneToMany association in User containing a List<Division>.

Check out this article for more details about mapping a one-to-many table relationship with JPA and Hibernate.


#3

Thanks for quick response.

But My scenario is different

Master table of User , Division and Sub-Division

User table

id name
1 x
2 y
3 z

Division table

id name
1 x
2 y
3 z

Sub-Division table

id name
1 a
2 b
3 c

Division To Sub-Division
id division_id sub_division_id
1 1 1
2 1 2

so on…

Finally when i create a user then assign particular division and sub-division.
Using following table
id user_id division_id sub_division_id
1 1 1 1
2 1 1 2
3 2 1 1

Drawback above table is linked in hibernate it will display all subdivision for every division. association only based on division id. but i need to associate with both user_id and division_id.

Above structure relationship is possible in hibernate for CRUD operation.


#4

Then, just map each entity as I already explained and use associations. If you read the Hibernate User Guide, you will find everything you need to map these associations. If you skip the User Guide and think you don’t need it, you’ll keep on bumping on issues both in development and production.


#5

Is this relationship is correct ?

Below

import java.io.Serializable;
import java.util.Date;
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.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;

import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonManagedReference;

@Entity
@Table(name=“users”)
public class User implements Serializable {

/**
 * 
 */
private static final long serialVersionUID = -692329857111290860L;

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="USER_ID")
private Long userId;

@Column(name="USER_NAME")
private String userName;


@JsonIgnore
@ManyToOne(cascade = CascadeType.ALL)
@JoinTable(name = "allocation",
    joinColumns = @JoinColumn(name = "user_id"),
    inverseJoinColumns = @JoinColumn(name = "division_id"))
private Division division;


@OneToMany(mappedBy = "subdivisions")
private List<Division> divisions;


public Long getUserId() {
	return userId;
}


public void setUserId(Long userId) {
	this.userId = userId;
}


public String getUserName() {
	return userName;
}


public void setUserName(String userName) {
	this.userName = userName;
}


public Division getDivision() {
	return division;
}


public void setDivision(Division division) {
	this.division = division;
}


public List<Division> getDivisions() {
	return divisions;
}


public void setDivisions(List<Division> divisions) {
	this.divisions = divisions;
}

}

package rc.demo.entities;

import java.io.Serializable;
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;

@Entity
@Table(name=“division”)
public class Division implements Serializable{

/**
 * 
 */
private static final long serialVersionUID = -6995167961351546190L;

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="DIVISION_ID")
private Long divisionId;

@Column(name="DIVISION_NAME")
private String divisionName;


@OneToMany(mappedBy = "division")
private List<SubDivision> subdivisions;


public Long getDivisionId() {
	return divisionId;
}


public void setDivisionId(Long divisionId) {
	this.divisionId = divisionId;
}


public String getDivisionName() {
	return divisionName;
}


public void setDivisionName(String divisionName) {
	this.divisionName = divisionName;
}


public List<SubDivision> getSubdivisions() {
	return subdivisions;
}


public void setSubdivisions(List<SubDivision> subdivisions) {
	this.subdivisions = subdivisions;
}

}

package rc.demo.entities;

import java.io.Serializable;
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.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import com.fasterxml.jackson.annotation.JsonIgnore;

@Entity
@Table(name=“subdivision”)
public class SubDivision implements Serializable{

/**
 * 
 */
private static final long serialVersionUID = -6646899508408570438L;

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="SUBDIVISION_ID")
private Long subdivisionId;

@Column(name="SUBDIVISION_NAME")
private String subdivisionName;

@JsonIgnore
@ManyToOne(cascade = CascadeType.ALL)
@JoinTable(name = "allocation",
    joinColumns = @JoinColumn(name = "subdivision_id"),
    inverseJoinColumns = @JoinColumn(name = "division_id"))
private Division division;

public Long getSubdivisionId() {
	return subdivisionId;
}

public void setSubdivisionId(Long subdivisionId) {
	this.subdivisionId = subdivisionId;
}

public String getSubdivisionName() {
	return subdivisionName;
}

public void setSubdivisionName(String subdivisionName) {
	this.subdivisionName = subdivisionName;
}

public Division getDivision() {
	return division;
}

public void setDivision(Division division) {
	this.division = division;
}

}

Final result like

[
{
“userId”: 1,
“userName”: “user1”,
“divisions”: []
},
{
“userId”: 1,
“userName”: “user1”,
“divisions”: []
},
{
“userId”: 1,
“userName”: “user1”,
“divisions”: []
},
{
“userId”: 1,
“userName”: “user1”,
“divisions”: []
},
{
“userId”: 1,
“userName”: “user1”,
“divisions”: []
},
{
“userId”: 2,
“userName”: “user2”,
“divisions”: []
},
{
“userId”: 2,
“userName”: “user2”,
“divisions”: []
}
]