Search code examples
javasqlormenumsdomain-model

Use Enum in domain model (ORM) when the corresponding table has set values?


I have a table named job_class which has set values:

This is the table definition:

create table job_class (
   job_class_code int NOT NULL PRIMARY KEY,
   job_class_name varchar(50) NOT NULL, 
   ext_code varchar(10) NOT NULL
)

It will always have 3 rows:

insert into job_class values (1, 'HOURLY', 'H')
insert into job_class values (2, 'SALARY', 'S')
insert into job_class values (3, 'EXECUTIVE', 'E')

job_class table is referenced as a FK in employee table:

create table employee (
   employee_id bigint NOT NULL PRIMARY KEY,
   first_name varchar(50) NOT NULL,
   middle_name varchar(50) NULL,
   last_name varchar(50) NOT NULL,
   job_class_code int NOT NULL FOREIGN KEY REFERENCES job_class (job_class_code)
)

Now to map this table in domain model (ORM), usually I define a class this way:

public class JobClass implements java.io.Serializable {
   private Integer id;
   private String name;
   private String extCode;

   public Integer getId() { return id; }
   public void setId(Integer id) { this.id = id; }

   public String getName() { return name; }
   public void setName(String name) { this.name = name; }

   public String getExtCode() { return extCode; }
   public void setId(String extCode) { this.extCode = extCode; }
}

But what if I define it as Enum instead:

public enum JobClass {
   HOURLY(1,"HOURLY","H"),
   SALARY(2,"SALARY","S"),
   EXECUTIVE(3,"EXECUTIVE","E");

   private Integer id;
   private String name;
   private String extCode;

   private JobClass(Integer id, String name, String extCode) {
      this.id = id;
      this.name = name;
      this.extCode = extCode;
   }

   public Integer getId() { return id; }
   public String getName() { return name; }
   public String getExtCode() { return extCode; }
}

Does it make sense to use a Enum in ORM? I have never used a ENUM directly in ORM before this way. Is it a good practice in this case? What are the Serializable implications if use Enum?


Solution

  • To use an enum you must be 100% sure that your table won't have new record or it's existing record altered, else you will get an error.

    With an ORM, you will be able to map to an enum via the @Enumerated annotation, there are way to do it : EnumType.ORDINAL or EnumType.STRING.

    I'll let you check the documentation for the difference.


    In your case since you are using the auto incremented id as a FK key, it would not be good to use @Enumerated(EnumType.STRING) as it would force you to name your enum values 1, 2 and 3.

    I don't really like to use @Enumerated(EnumType.ORDINAL) as it ties your enum order with the database table order. But in your case it would work.

    If you want to go the extra miles, you could use a converter @Convert(converter = JobClassConverter.class)

    You would keep your enum as it is and the employee's jobClass attribut would look like that :

      @Column(name = "job_class_code")
      @Convert(converter = JobClassConverter.class)
      private JobClass jobClass;
    

    Then you would create the JobClassConverter

    public class JobClassConverter implements AttributeConverter<JobClass, Integer> {
    
        @Override
        public Integer convertToDatabaseColumn(final JobClass pAttribute) {
            if (pAttribute == null) {
                return null;
            } else {
                switch (pAttribute) {
                    case HOURLY:
                        return 1;
                    case SALARY:
                        return 2;
                    case EXECUTIVE:
                        return 3;
                }
            }
        }
    
        @Override
        public JobClass convertToEntityAttribute(final Integer pDbData) {
            if (pDbData == null) {
                return null;
            } else {
                switch (pDbData) {
                    case 1:
                        return JobClass.HOURLY;
                    case 2:
                        return JobClass.SALARY;
                    case 3:
                        return JobClass.EXECUTIVE;
                }
            }
        }
    }