In lack of a SQL enum type an unfortunately somewhat popular database design pattern seems to be to create one table for all enum values (thank you for the link, Nathan). I have seen many variations of this over the years, but the one that I'm currently struggling with looks something like this:
ID | ENUM | VALUE
-----+-------------+----------
1 | DAY_OF_WEEK | SUNDAY
2 | DAY_OF_WEEK | MONDAY
...
7 | DAY_OF_WEEK | SATURDAY
...
18 | PERSON_TYPE | EMPLOYEE
19 | PERSON_TYPE | MANAGER
Which is then used like this - for example in a table of persons:
ID | NAME | TYPE
----+----------+------
1 | Jane Doe | 19
Meaning that Jane is a manger because 19 is the primary key of the person type "manager" in the enum table.
Using JPA (2.1), is there an elegant way to map this construct to a propper Java enum?
Important: There are many versions of my "enum table" out in the wild with different primary key values, i.e. "manager" might sometimes be row #19, but sometimes row #231. However, the values never change at runtime. Changing the database schema is unfortunately also not an option, but using proprietary features of any JPA provider would be an option.
I actually found a solution that worked but that was too hacky for my liking:
public enum PersonType { EMPLOYEE, MANAGER }
@Table(name="PERSONS") @Entity public class Persons {
@Id @Column(name="ID") long id;
@Column(name="NAME") String name;
@Convert(converter = PtConv.class) @Column(name="TYPE") PersonType type;
// ...
}
@Converter public class PtConv implements AttributeConverter<PersonType, Integer> {
// In a static initializer run a JDBC query to fill these maps:
private static Map<Integer, PersonType> dbToJava;
private static Map<PersonType, Integer> javaToDb;
@Override public Integer convertToDatabaseColumn(PersonType attribute) {
return javaToDb.get(attribute);
}
@Override public PersonType convertToEntityAttribute(Integer dbData) {
return dbToJava.get(dbData);
}
}
I would have lived with this if CDI was available in @Converter
s - but with the static construct testing was a nightmare.
The Java™ Persistence API (JPA) provides a mechanism for managing persistence and object-relational mapping and functions since the EJB 3.0 specifications. The JPA specification defines the object-relational mapping internally, rather than relying on vendor-specific mapping implementations.
A JPA (Java Persistence API) is a specification of Java which is used to access, manage, and persist data between Java object and relational database. It is considered as a standard approach for Object Relational Mapping. JPA can be seen as a bridge between object-oriented domain models and relational database systems.
What is JPA? Spring Boot JPA is a Java specification for managing relational data in Java applications. It allows us to access and persist data between Java object/ class and relational database. JPA follows Object-Relation Mapping (ORM).
JDBC allows us to write SQL commands to read data from and update data to a relational database. JPA, unlike JDBC, allows developers to construct database-driven Java programs utilizing object-oriented semantics.
For reference this is how I solved the problem. Proper Java enums would be my preference, and I will accept any answer that is better than this.
@Table(name="PERSONS") @Entity public class Persons {
@Id @Column(name="ID") long id;
@Column(name="NAME") String name;
@Column(name="TYPE") BaseEnum type; // known to be "PersonTypeEnum"
public PersonType getType() {
switch(type.getValue()) {
case "EMPLOYEE": return PersonType.EMPLOYEE;
case "MANAGER": return PersonType.MANAGER;
}
throw new IllegalStateException();
}
public void setType(PersonTypeEnum type) {
this.type = type;
}
// ...
}
@Entity @Inheritance @DiscriminatorColumn(name="ENUM") @Table(name="ENUMS")
public abstract class BaseEnum {
@Id private int id;
@Column(name="VALUE") String value;
// ...
}
@Entity @DiscriminatorValue("PERSON_TYPE")
public class PersonTypeEnum extends BaseEnum { }
So the getters and the setters for enum values have different types, and setting the value requires having a reference to the entity which further blows up the code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With