Java JPA/Hibernate-将枚举持久化为常量表
目前,我正在使用标准方法将枚举映射到Hibernate,例如Java JPA/Hibernate-将枚举持久化为常量表,java,hibernate,jpa,enums,Java,Hibernate,Jpa,Enums,目前,我正在使用标准方法将枚举映射到Hibernate,例如 @Entity public class Job { @Enumerated(EnumType.STRING) protected State state; } public enum State{ NEW,OLD; } 现在需求发生了变化,我必须创建一个表State,其中包含作为字符串常量的枚举的所有有效值。因此作业必须参考状态表。我不必迁移遗留数据 我必须用JPA/Hibernate映射哪些选项 是否可
@Entity
public class Job {
@Enumerated(EnumType.STRING)
protected State state;
}
public enum State{
NEW,OLD;
}
现在需求发生了变化,我必须创建一个表State
,其中包含作为字符串常量的枚举的所有有效值。因此作业
必须参考状态
表。我不必迁移遗留数据
状态表(1->“新建”,2->“旧”)。
在DDL生成期间
我觉得这没什么道理。
enum
的值是静态和常量,而SQL表中的值是动态的。如果DB不包含此类枚举的确切值(不多也不少),该怎么办
编辑:如果你被迫实施它,像这样的事情可能会奏效吗
public enum State{
int primaryKey;
NEW(0),OLD(1);
public State(int pk) {
primarykey = pk;
}
}
然后通过主键联接….最终得到一个解决方案,该解决方案生成DDL,包括枚举常量和外键约束 e、 g 使用以下
MetadataContributor
(/src/main/resources/META-INF/services/org.hibernate.boot.spi.MetadataContributor)就足够了:
公共类EnumConstantsMetadataContributor实现MetadataContributor{
私有最终静态记录器日志=LoggerFactory.getLogger(EnumConstantMetadataContributor.class);
私有最终静态列表启用_ON=Arrays.asList(“验证”、“更新”、“创建”、“创建删除”);
私有最终静态整数默认值\u VARCHAR\u SIZE=255;
私有最终静态标识符默认\列\名称=Identifier.toIdentifier(“枚举\常量”,false);
@凌驾
public void贡献(InFlightMetadataCollector metadataCollector,IndexView-jandexIndex){
if(应该运行(metadataCollector)){
AddenumStableConsTantsAndFkConstraint(metadataCollector);
}
}
私有布尔值应运行(InFlightMetadataCollector metadataCollector){
StandardServiceRegistry serviceRegistry=metadataCollector.getMetadataBuildingOptions().getServiceRegistry();
ConfigurationService config=serviceRegistry.getService(ConfigurationService.class);
String setting=config.getSetting(AvailableSettings.HBM2DDL_AUTO,String.class,null);
返回(设置!=null | |启用_ON.contains(设置));
}
私有void AddenumStableConsTantsAndFkConstraint(InFlightMetadataCollector metadataCollector){
for(PersistentClass PersistentClass:metadataCollector.getEntityBindings()){
类plainJavaClass=persistentClass.getMappedClass();
if(Enum.class.isAssignableFrom((plainJavaClass))){
createEnumInsertsAndDbColumns(persistentClass、plainJavaClass、metadataCollector);
}
tryAddFkConstraint(persistentClass,metadataCollector);
}
}
私有void tryAddFkConstraint(PersistentClass PersistentClass,InFlightMetadataCollector metadataCollector){
消费者createEnumFkConstraintForField=字段->{
字符串fieldName=field.getName();
PersistentClass targetPersistentClass=metadataCollector.getEntityBinding(field.getType().getCanonicalName());
if(targetPersistentClass==null){
error(“Target(enum)类必须是@Entity:{}”,field.getType().getCanonicalName());
系统出口(1);
}
属性enumReferenceAnnotatedProperty=persistentClass.getProperty(字段名);
persistentClass.getTable().createForeignKey(null,
Arrays.asList(enumReferenceAnnotatedProperty.getColumnIterator().next()),
targetPersistentClass.getEntityName());
};
Field[]declaredFields=persistentClass.getMappedClass().getDeclaredFields();
of(declaredFields).filter(field->field.isAnnotationPresent(EnumReference.class)).forEach(
createEnumFkConstraintForField);
}
私有void createEnumInsertsAndDbColumns(PersistentClass PersistentClass、Class clazz、,
InFlightMetadataCollector元数据){
字符串tableName=persistentClass.getTable().getName();
Enum[]enumJavaConstants=clazz.asSubclass(Enum.class).getEnumConstants();
ArrayList insertCommandAccumulator=新的ArrayList(enumJavaConstants.length);
可选enumValueAnnotatedField=of(enumJavaConstants.getClass().getComponentType().getDeclaredFields())
.filter(field->field.isAnnotationPresent(EnumValue.class)).map(fieldWithEnumValue->{
fieldWithEnumValue.setAccessible(true);
返回带有枚举值的字段;
}).findAny();//只支持一个或一个
if(enumValueAnnotatedField.isPresent()){
SetMinimalFieldLengthoExitingColumn(enumValueAnnotatedField.get(),enumJavaConstants,persistentClass);
}
for(int i=0;igetInstanceValueOfEnumValueAnnotation(it,v))
.orElse(it.name());
如果(!enumValueAnnotatedField.isPresent()){
insertAdditionalColumn(persistentClass、metadata.getDatabase()、enumJavaConstants);
}
add(createInsert(tableName,i,constantEnumValue));
}
InitCommand InitCommand=newinitcommand(insertCommandAccumulator.toArray(新字符串[0]);
persistentClass.getTable().addInitCommand(initCommand);
}
私有void setMinimalFieldLengthOfExitingColumn(字段字段,枚举[]enumJavaConstants,
PersistentClass(PersistentClass){
Property=persistentClass.getProperty(field.getName());
Column Column=persistentClass.getTable().getColumn(标识符.t
@Entity
public enum MyEnum{
@EnumValue
private String name;
@Id
private int id;
}
@Entity
public class MyEntity {
@EnumReference
protected MyEnum myEnum;
}
public class EnumConstantsMetadataContributor implements MetadataContributor {
private final static Logger LOG = LoggerFactory.getLogger(EnumConstantsMetadataContributor.class);
private final static List<String> ENABLED_ON = Arrays.asList("validate", "update", "create", "create-drop");
private final static Integer DEFAULT_VARCHAR_SIZE = 255;
private final static Identifier DEFAULT_COLUMN_NAME = Identifier.toIdentifier("enum_constant", false);
@Override
public void contribute(InFlightMetadataCollector metadataCollector, IndexView jandexIndex) {
if (shouldRun(metadataCollector)) {
addEnumsAsTableConstantsAndFkConstraint(metadataCollector);
}
}
private boolean shouldRun(InFlightMetadataCollector metadataCollector) {
StandardServiceRegistry serviceRegistry = metadataCollector.getMetadataBuildingOptions().getServiceRegistry();
ConfigurationService config = serviceRegistry.getService(ConfigurationService.class);
String setting = config.getSetting(AvailableSettings.HBM2DDL_AUTO, String.class, null);
return (setting != null || ENABLED_ON.contains(setting));
}
private void addEnumsAsTableConstantsAndFkConstraint(InFlightMetadataCollector metadataCollector) {
for (PersistentClass persistentClass : metadataCollector.getEntityBindings()) {
Class<?> plainJavaClass = persistentClass.getMappedClass();
if (Enum.class.isAssignableFrom((plainJavaClass))) {
createEnumInsertsAndDbColumns(persistentClass, plainJavaClass, metadataCollector);
}
tryAddFkConstraint(persistentClass, metadataCollector);
}
}
private void tryAddFkConstraint(PersistentClass persistentClass, InFlightMetadataCollector metadataCollector) {
Consumer<Field> createEnumFkConstraintForField = field -> {
String fieldName = field.getName();
PersistentClass targetPersistentClass = metadataCollector.getEntityBinding(field.getType().getCanonicalName());
if (targetPersistentClass == null) {
LOG.error("Target (enum) class must be an @Entity: {}", field.getType().getCanonicalName());
System.exit(1);
}
Property enumReferenceAnnotatedProperty = persistentClass.getProperty(fieldName);
persistentClass.getTable().createForeignKey(null,
Arrays.asList(enumReferenceAnnotatedProperty.getColumnIterator().next()),
targetPersistentClass.getEntityName());
};
Field[] declaredFields = persistentClass.getMappedClass().getDeclaredFields();
of(declaredFields).filter(field -> field.isAnnotationPresent(EnumReference.class)).forEach(
createEnumFkConstraintForField);
}
private void createEnumInsertsAndDbColumns(PersistentClass persistentClass, Class<?> clazz,
InFlightMetadataCollector metadata) {
String tableName = persistentClass.getTable().getName();
Enum<?>[] enumJavaConstants = clazz.asSubclass(Enum.class).getEnumConstants();
ArrayList<String> insertCommandAccumulator = new ArrayList<String>(enumJavaConstants.length);
Optional<Field> enumValueAnnotatedField = of(enumJavaConstants.getClass().getComponentType().getDeclaredFields())
.filter(field -> field.isAnnotationPresent(EnumValue.class)).map(fieldWithEnumValue -> {
fieldWithEnumValue.setAccessible(true);
return fieldWithEnumValue;
}).findAny(); // just none or one is supported
if (enumValueAnnotatedField.isPresent()) {
setMinimalFieldLengthOfExitingColumn(enumValueAnnotatedField.get(), enumJavaConstants, persistentClass);
}
for (int i = 0; i < enumJavaConstants.length; i++) {
Enum<?> it = enumJavaConstants[i];
String constantEnumValue = enumValueAnnotatedField.map(v -> getInstanceValueOfEnumValueAnnotation(it, v))
.orElse(it.name());
if (!enumValueAnnotatedField.isPresent()) {
insertAdditionalColumn(persistentClass, metadata.getDatabase(), enumJavaConstants);
}
insertCommandAccumulator.add(createInsert(tableName, i, constantEnumValue));
}
InitCommand initCommand = new InitCommand(insertCommandAccumulator.toArray(new String[0]));
persistentClass.getTable().addInitCommand(initCommand);
}
private void setMinimalFieldLengthOfExitingColumn(Field field, Enum<?>[] enumJavaConstants,
PersistentClass persistentClass) {
Property property = persistentClass.getProperty(field.getName());
Column column = persistentClass.getTable().getColumn(Identifier.toIdentifier(property.getName()));
Integer maxLengthOfEnums = maxLengthOfEnums(enumJavaConstants,
e -> getInstanceValueOfEnumValueAnnotation(e, field));
column.setLength(maxLengthOfEnums);
}
private String getInstanceValueOfEnumValueAnnotation(Enum<?> myEnum, Field enumValueAnnotatedField) {
try {
return enumValueAnnotatedField.get(myEnum).toString();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
return null;
}
}
private static Integer maxLengthOfEnums(Enum<?>[] enums, Function<Enum<?>, String> enumConstantValueExtractor) {
return of(enums).map(it -> enumConstantValueExtractor.apply(it).length()).reduce(Math::max)
.orElse(DEFAULT_VARCHAR_SIZE);
};
private void insertAdditionalColumn(PersistentClass persistentClass, Database database, Enum<?>[] enumJavaConstants) {
Integer maxEnumStringLength = maxLengthOfEnums(enumJavaConstants, c -> c.name());
Column column = new Column(DEFAULT_COLUMN_NAME.render(database.getDialect()));
String typeName = database.getDialect().getTypeName(Types.VARCHAR, maxEnumStringLength, 0, 0);
column.setSqlType(typeName);
persistentClass.getTable().addColumn(column);
}
private String createInsert(String tableName, int position, String dbEnumValue) {
return ("insert into " + tableName + " values(" + position + ",\'" + dbEnumValue + "\')");
}
}