Search This Blog

Tuesday, 15 October 2013

Saving an Enum in JPA

Consider the below entity:
@Table(name = "STUDENT")
public class Student {
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 private Long id;
 @Column(name = "NAME")
 private String name;
 private Rating rating;
//setter getters
where Rating is a simple Enum
public enum Rating {
I tried to save an object of Student in the the database:
public static void testCreate() {
 EntityManager entityManager = emFactory.createEntityManager();
 EntityTransaction transaction = entityManager.getTransaction();
 Student student = new Student();
If we ran this code the record would be ......................... SAVED
This is actually pretty cool. I actually thought this might be some easy facility provided by Hibernate, but the JPA docs indicate differently. JPA will automatically save Enum properties to the database.
I ran the code with table creation enabled. This is what was created in PostGRE SQL.
3015 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport  - 
    create table firstOne.STUDENT (
        id  bigserial not null,
        NAME varchar(255),
        rating int4,
        primary key (id)
JPA requires that the ORM map any enum present in the entity with the value of the ordinal property. Since the value we used (MUST_MEET) occurred as the third value in the class, the record in the table held the value 2. (Ordinal for Enums are 0 based)
There is a problem with this approach though. If we accidentally modified the sequence of the constants in the java file, it would make a mess of the records in the database.
The alternative is to use the enum values instead of the ordinals.
@Table(name = "ADRESSED_USER")
public class User {
 private Rating rating;
// remaining code
The table now generated is:
3797 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport  - 
    create table firstOne.STUDENT (
        id  bigserial not null,
        NAME varchar(255),
        rating varchar(255),
        primary key (id)
The rating column is now a string column. If we look at the insert SQL now:
        (NAME, rating) 
        (?, ?)
What if we need to get all records of a particular rating ?
public static void findMustMeet() {
 EntityManager entityManager = emFactory.createEntityManager();
 final Query query = entityManager
  .createQuery("SELECT student FROM Student as student " +
   "WHERE student.rating = :rating");
 query.setParameter("rating", Rating.MUST_MEET);
The code executes a JPA Query to return a record with a RATING of MUST_MEET. The logs indicate the same:
5328 [main] DEBUG org.hibernate.engine.query.HQLQueryPlan  - HQL param location 
recognition took 31 mills (SELECT student FROM Student as student WHERE student.
rating = :rating)
5375 [main] DEBUG org.hibernate.SQL  - 
    select as id0_,
        student0_.NAME as NAME0_,
        student0_.rating as rating0_ 
        firstOne.STUDENT student0_ 
        student0_.rating=? limit ?
5375 [main] DEBUG org.hibernate.type.EnumType  - Binding 'MUST_MEET' to paramete
r: 1

1 comment: