JPA和enum表(又名"一个真正的查找表")

Til*_*ilo 8 java orm jpa-2.1

问题

由于缺少SQL枚举类型,不幸的是有些流行的数据库设计模式似乎是所有枚举值创建一个表(感谢您的链接,Nathan).多年来我看到了很多这种变化,但我目前正在努力解决的问题看起来像这样:

 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
Run Code Online (Sandbox Code Playgroud)

然后将其用于此类 - 例如在人员表中:

 ID | NAME     | TYPE
----+----------+------
  1 | Jane Doe | 19     
Run Code Online (Sandbox Code Playgroud)

这意味着Jane是一个管理器,因为19是enum表中人员类型"manager"的主键.

使用JPA(2.1),是否有一种优雅的方法将此构造映射到propper Java枚举?

重要提示:我的"枚举表"有许多版本在野外,具有不同的主键值,即"经理"有时可能是第19行,但有时排第231行.但是,值在运行时永远不会更改.遗憾的是,更改数据库模式也不是一种选择,但使用任何JPA提供程序的专有功能都是一种选择.

什么有效

我实际上找到了一个有效的解决方案,但这对我来说太难了:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

如果CDI在@Converters 中可用,我会和它一起生活- 但静态构造测试是一场噩梦.

Til*_*ilo 1

作为参考,这就是我解决问题的方法。正确的 Java 枚举将是我的偏好,我会接受任何比这更好的答案。

@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 { }
Run Code Online (Sandbox Code Playgroud)

因此,枚举值的 getter 和 setter 具有不同的类型,并且设置值需要引用实体,这会进一步破坏代码。