Sunday, December 25, 2016

Embedded entities and collections in Hibernate JPA

Sometimes the JPA model may differ from the database model. The JPA model may include embedded entities and embedded collections of entities.
The embedded entity is a Java class, which encapsulates mapping of a group of columns without binding to the particular table. The same embedded entity may be used in different JPA entities.

The embedded entity is a Java class with the @Embeddable annotation.
The embedded collection is a container of embeddable entities.

Embedded collection vs OneToMany relation


The embedded collection is the alternative to the OneToMany relation.
The OneToMany relation is between two JPA entities. The embedded collection contains embedded entities(not JPA entities) and it is used by a JPA entity.

The embeddable class cannot to be used for embedded collection, if it has a column with the @ID annotation.

Embedded entities example

Let's see an example of using the embedded entities.

DB Schema


The DB schema contains 3 tables: COUNTRY, PROBLEM_CATEGORY and PROBLEM_SUBCATEGORY:
 CREATE TABLE `MY_DB`.`COUNTRY` (  
  `ID` int(11) unsigned NOT NULL auto_increment,  
  `CODE` varchar(20) NOT NULL,  
  `NAME` varchar(100) NOT NULL,  
  CONSTRAINT `PRIMARY` PRIMARY KEY (`ID`)  
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

 CREATE TABLE `MY_DB`.`PROBLEM_CATEGORY` (  
  `ID` int(11) unsigned NOT NULL auto_increment,  
  `CODE` varchar(20) NOT NULL,  
  `NAME` varchar(100) NOT NULL,  
  CONSTRAINT `PRIMARY` PRIMARY KEY (`ID`)  
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  
 CREATE TABLE `MY_DB`.`PROBLEM_SUBCATEGORY` (  
  `ID` int(11) unsigned NOT NULL auto_increment,  
  `CATEGORY_ID` int(11) unsigned NOT NULL,  
  `CODE` varchar(20) NOT NULL,  
  `NAME` varchar(100) NOT NULL,  
  CONSTRAINT `PRIMARY` PRIMARY KEY (`ID`),  
  CONSTRAINT `FK_SUBCATEGORY_CATEGORY_ID` FOREIGN KEY (`CATEGORY_ID`) REFERENCES `MY_DB`.`PROBLEM_CATEGORY` (`ID`) ON DELETE CASCADE ON UPDATE NO ACTION  
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;  
All the tables have a pair of similar columns: CODE and NAME.
Each record of the PROBLEM_CATEGORY table may have several associated records in the PROBLEM_SUBCATEGORY table. This relation is specified with the foreign key at PROBLEM_SUBCATEGORY table.

JPA Model

The class DbCodeNamePair implements an embeddable entity for CODE and NAME columns:
 @Embeddable  
 public class DbCodeNamePair {  
      private String code;  
      private String name;  
      public DbCodeNamePair() {  
      }  
      @Column(name="CODE", nullable=false)  
      public String getCode() {  
           return code;  
      }  
      public void setCode(String code) {  
           this.code = code;  
      }  
      @Column(name="NAME", nullable=false)  
      public String getName() {  
           return name;  
      }  
      public void setName(String name) {  
           this.name = name;  
      }  
 }  
The DbCountry is the JPA entity and implements mapping for the table COUNTRY. It embeds the DbCodeNamePair instead of direct mapping to the CODE and NAME columns:
 @Table(name="COUNTRY")  
 @Entity  
 @Access(AccessType.PROPERTY)  
 public class DbCountry {  
      private int id;  
      private DbCodeNamePair codeNamePair;  
      @Id  
      @GeneratedValue  
      @Column(name="ID")  
      public int getId() {  
           return id;  
      }  
      public void setId(int id) {  
           this.id = id;  
      }  
      @Embedded   
      public DbCodeNamePair getCodeNamePair() {  
           return codeNamePair;  
      }  
      public void setCodeNamePair(DbCodeNamePair codeNamePair) {  
           this.codeNamePair = codeNamePair;  
      }  
 }  
The DbProblemCategory is the JPA entity and implements mapping for the table PROBLEM_CATEGORY. It embeds the DbCodeNamePair instead of direct mapping to the CODE and NAME columns and a collection of embedded entities of type DbProblemSubCategory:
 @Entity  
 @Table(name="PROBLEM_CATEGORY")  
 @Access(AccessType.PROPERTY)  
 public class DbProblemCategory {  
      private int id;  
      private DbCodeNamePair codeNamePair;  
      private List<DbProblemSubCategory> subCategories;  
      @Id  
      @GeneratedValue  
      @Column(name="ID")  
      public int getId() {  
           return id;  
      }  
      public void setId(int id) {  
           this.id = id;  
      }  
      @Embedded   
      public DbCodeNamePair getCodeNamePair() {  
           return codeNamePair;  
      }  
      public void setCodeNamePair(DbCodeNamePair codeNamePair) {  
           this.codeNamePair = codeNamePair;  
      }  
      @ElementCollection(fetch = FetchType.EAGER)  
      @CollectionTable(  
                name="PROBLEM_SUBCATEGORY",  
                joinColumns=@JoinColumn(name="CATEGORY_ID"))  
      public List<DbProblemSubCategory> getSubCategories() {  
           return subCategories;  
      }       
      public void setSubCategories(List<DbProblemSubCategory> subCategories) {  
           this.subCategories = subCategories;  
      }  
 }  
The embeddable entity DbProblemSubCategory implements mapping for the table PROBLEM_SUBCATEGORY and itself embeds another embeddable - the DbCodeNamePair instead of direct mapping to the CODE and NAME columns:
 @Embeddable  
 @Access(AccessType.PROPERTY)  
 public class DbProblemSubCategory {  
      private int id;  
      private DbCodeNamePair codeNamePair;  
      @Column(name="ID")  
      public int getId() {  
           return id;  
      }  
      public void setId(int id) {  
           this.id = id;  
      }  
      @Embedded   
      public DbCodeNamePair getCodeNamePair() {  
           return codeNamePair;  
      }  
      public void setCodeNamePair(DbCodeNamePair codeNamePair) {  
           this.codeNamePair = codeNamePair;  
      }  
 }  
The DbProblemSubCategory cannot be ever used as the JPA entity:
- it does not have either @Entity or @Table annotation;
- it does not specify which table it maps;
- it does not have any column with the annotation @ID.

2 comments :

for IT the said...

Enjoyed your approach to explaining how it works, hope to see more blog posts from you. thank you!

Hibernate Online Training

Ala Schneider said...

I am happy it was helpful

About the author

My Photo
I trust only simple code and believe that code should be handsome. This is not a matter of technology, but professional approach, consolidated after years of software development. I enjoy to cause things working and feel very happy, when I manage to solve a problem.
Back to Top