#java #hibernate #jpa #spring-data-jpa #spring-data
#java #спящий режим #jpa #spring-data-jpa #весна-данные
Вопрос:
Я работаю над микросервисом, который раньше имел один вид перечисления, связанный с одним из его столбцов, но теперь мне пришлось его изменить.
@Convert(converter = TypeEnumConverter.class)
@Enumerated(EnumType.STRING)
@Column(name = "TIPO", length = 40, nullable = false)
private TypeEnum type;
Он отображается таким образом, но имена и типы перечислений несовместимы, есть ли способ сказать JPA игнорировать его, если он не может преобразовать обратно в это перечисление?
Комментарии:
1. что вы подразумеваете под «игнорировать это»? установите
type
для поля значениеnull
?2. ДА. Он пытается преобразовать недопустимый тип (из базы данных, более старый тип перечисления), и это вызывает исключение IllegalArgumentException.
Ответ №1:
Вы можете реализовать пользовательское сопоставление перечислений с помощью AttributeConverter . Затем внутри конвертера вы можете сопоставить неизвестные значения enum с null
. Но, пожалуйста, имейте в виду, что следующая операция обновления приведет к удалению значения из этого столбца базы данных.
Вы уже ссылаетесь на свой TypeEnumConverter
преобразователь атрибутов в @Convert
аннотации в вашем отображении. Если вы хотите его использовать, вам нужно удалить @Enumerated
аннотацию. Спецификация JPA не позволяет вам использовать эти 2 аннотации вместе, потому что обе определяют, как сопоставляются значения Enum.
Пример реализации
Вот пример того, как может выглядеть такое сопоставление.
Мое перечисление
Я использую это простое Vehicle
перечисление:
public enum Vehicle {
BUS, CAR, TRAIN, PLANE;
}
Мой конвертер атрибутов
Конвертер атрибутов реализует сопоставление между объектом Java и значением, хранящимся в вашей базе данных. Это простой класс Java, который реализует AttributeConverter
интерфейс и снабжен @Converter
аннотациями . Если вы установите autoApply
для атрибута значение true, он будет автоматически использоваться для всех атрибутов сущности преобразованного типа.
@Converter(autoApply = true)
public class VehicleConverter implements AttributeConverter<Vehicle, String> {
@Override
public String convertToDatabaseColumn(Vehicle vehicle) {
switch (vehicle) {
case Vehicle.BUS:
return "B";
case Vehicle.CAR:
return "C";
case Vehicle.TRAIN:
return "T";
case Vehicle.PLANE:
return "P";
}
}
@Override
public Vehicle convertToEntityAttribute(String dbData) {
switch (dbData) {
case "B":
return Vehicle.BUS;
case "C":
return Vehicle.CAR;
case "T":
return Vehicle.TRAIN;
case "P":
return Vehicle.PLANE;
default:
// ignore unknown values
return null;
}
}
}
Мой класс сущности
Затем вы можете использовать перечисление без каких-либо дополнительных аннотаций сопоставления в вашем классе сущностей.
@Entity
public class Trip {
private Vehicle vehicle;
...
}
Комментарии:
1. Вы сказали: но, пожалуйста, имейте в виду, что следующая операция обновления затем удалит значение из этого столбца базы данных. Что именно вы имели в виду под этим?
2. Если ваш AttributeConverter устанавливает значение атрибута равным null, а ваш бизнес-код изменяет любой из других атрибутов объекта, Hibernate сгенерирует инструкцию SQL UPDATE и установит значение преобразованного перечисления равным null.
Ответ №2:
Если вы не возражаете потерять устаревшие значения в БД, которые несовместимы с текущим перечислением, тогда ответ @Thorben — это правильный путь.
Если вы хотите сохранить их, то одним из решений было бы объявить ваше поле как строку и предоставить вспомогательные методы для управления значением в виде перечисления. Что-то вроде:
@Column(name = "TIPO", length = 40, nullable = false)
private String type;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public TypeEnum getTypeEnum() {
try {
return TypeEnum.valueOf(type);
} catch (IllegalArgumentException e) {
return null;
}
}
public void setTypeEnum(TypeEnum typeEnum) {
if (typeEnum != null) {
type = typeEnum.toString();
}
}