JPA의 맵 열거형(고정값 포함)을 지정하시겠습니까?
JPA를 사용하여 열거형을 매핑하는 다른 방법을 찾고 있습니다.특히 각 열거 엔트리의 정수 값을 설정하고 정수 값만 저장합니다.
@Entity
@Table(name = "AUTHORITY_")
public class Authority implements Serializable {
public enum Right {
READ(100), WRITE(200), EDITOR (300);
private int value;
Right(int value) { this.value = value; }
public int getValue() { return value; }
};
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "AUTHORITY_ID")
private Long id;
// the enum to map :
private Right right;
}
간단한 해결책은 EnumType과 함께 Enumerated 주석을 사용하는 것입니다.순서:
@Column(name = "RIGHT")
@Enumerated(EnumType.ORDINAL)
private Right right;
단, 이 경우 JPA는 원하는 값(100,200,300)이 아닌 열거 인덱스(0,1,2)를 매핑합니다.
내가 찾은 두 가지 해결책은 간단해 보이지 않는다...
첫 번째 솔루션
여기서 제안하는 솔루션은 @PrePersist 및 @PostLoad를 사용하여 열거형을 다른 필드로 변환하고 열거형 필드를 임시로 마킹합니다.
@Basic
private int intValueForAnEnum;
@PrePersist
void populateDBFields() {
intValueForAnEnum = right.getValue();
}
@PostLoad
void populateTransientFields() {
right = Right.valueOf(intValueForAnEnum);
}
두 번째 솔루션
여기서 제안된 두 번째 솔루션은 범용 변환 개체를 제안했지만 여전히 무겁고 최대 절전 모드 지향으로 보입니다(@Type은 Java EE에는 존재하지 않는 것 같습니다).
@Type(
type = "org.appfuse.tutorial.commons.hibernate.GenericEnumUserType",
parameters = {
@Parameter(
name = "enumClass",
value = "Authority$Right"),
@Parameter(
name = "identifierMethod",
value = "toInt"),
@Parameter(
name = "valueOfMethod",
value = "fromInt")
}
)
다른 해결 방법이 있습니까?
몇 가지 아이디어가 있는데 JPA에 있는지 모르겠습니다.
- Authority 객체를 로드 및 저장할 때 Authority 클래스의 오른쪽 멤버의 setter 및 getter 메서드를 사용합니다.
- 열거형을 int로, int를 enum으로 변환하는 Right enum의 메서드가 무엇인지 JPA에 알려주는 것도 같은 생각입니다.
- Spring을 사용하고 있기 때문에 JPA에 특정 컨버터(Right Editor)를 사용하도록 지시하는 방법은 없습니까?
2.는 Enum을 을 JPA 2.1 Enum으로합니다.name
그들의 는 their their에 ordinal
JPA를 사용하다 ★★★★★★★★★★★★★★★★:
- 변환을 내선 「Hibernate」의 「Hibernate」의 「Hibernate」, 「Hibernate」의 「Hibernate」의 「Hibernate」를 사용할 .
UserType
Link , Eclipse 링크Converter
( 째 ( ( ( ( ( ( )에~~에~ - @PrePersist 및 @PostLoad 트릭(첫 번째 솔루션)을 사용해야 합니다.~또는~
- 에 주석을 달아 getter를 getter를 한다.
int
는~는~는~는~는~는~는~는~는~는~하다. - 엔티티 수준에서 정수 속성을 사용하여 getter 및 setter로 변환을 수행합니다.
최신 옵션에 대해 설명하겠습니다(기본 구현이므로 필요에 따라 조정하십시오).
@Entity
@Table(name = "AUTHORITY_")
public class Authority implements Serializable {
public enum Right {
READ(100), WRITE(200), EDITOR (300);
private int value;
Right(int value) { this.value = value; }
public int getValue() { return value; }
public static Right parse(int id) {
Right right = null; // Default
for (Right item : Right.values()) {
if (item.getValue()==id) {
right = item;
break;
}
}
return right;
}
};
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "AUTHORITY_ID")
private Long id;
@Column(name = "RIGHT_ID")
private int rightId;
public Right getRight () {
return Right.parse(this.rightId);
}
public void setRight(Right right) {
this.rightId = right.getValue();
}
}
이것은, JPA 2.1 로 실현되었습니다.
@Column(name = "RIGHT")
@Enumerated(EnumType.STRING)
private Right right;
상세:
- https://dzone.com/articles/mapping-enums-done-right
- http://www.thoughts-on-java.org/jpa-21-how-to-implement-type-converter/
JPA 2.1부터는 Attribute Converter를 사용할 수 있습니다.
다음과 같이 열거된 클래스를 만듭니다.
public enum NodeType {
ROOT("root-node"),
BRANCH("branch-node"),
LEAF("leaf-node");
private final String code;
private NodeType(String code) {
this.code = code;
}
public String getCode() {
return code;
}
}
그리고 다음과 같은 컨버터를 만듭니다.
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
@Converter(autoApply = true)
public class NodeTypeConverter implements AttributeConverter<NodeType, String> {
@Override
public String convertToDatabaseColumn(NodeType nodeType) {
return nodeType.getCode();
}
@Override
public NodeType convertToEntityAttribute(String dbData) {
for (NodeType nodeType : NodeType.values()) {
if (nodeType.getCode().equals(dbData)) {
return nodeType;
}
}
throw new IllegalArgumentException("Unknown database value:" + dbData);
}
}
필요한 엔티티:
@Column(name = "node_type_code")
부탁드립니다.@Converter(autoApply = true)
컨테이너에 따라 다를 수 있지만 Wildfly 8.1.0에서 작동하도록 테스트되었습니다.않는 는, 「 」 「 」 「 」를 할 수 .@Convert(converter = NodeTypeConverter.class)
엔티티 클래스 컬럼에 표시됩니다.
가장 좋은 방법은 ORDINAL과 STRING의 함정을 피하기 위해 각 열거형에 고유 ID를 매핑하는 것입니다. 열거형을 매핑하는 5가지 방법을 개략적으로 설명하는 이 게시물을 참조하십시오.
위 링크에서 가져온 내용:
1 & 2. @Enumerated 사용
현재 @Enumerated 주석을 사용하여 JPA 엔티티 내에서 Enum을 매핑할 수 있는 방법은 두 가지가 있습니다.안타깝게도 둘 다 Enum Type입니다.STRING 및 EnumType.Ordinal에는 한계가 있습니다.
EnumType을 사용하는 경우.그런 다음 열거형 중 하나의 이름을 바꾸면 열거형 값이 데이터베이스에 저장된 값과 동기화되지 않습니다.EnumType을 사용하는 경우.ORDINAL을 사용하면 열거형 내의 유형을 삭제 또는 재정렬하면 데이터베이스에 저장된 값이 잘못된 Enum 유형에 매핑됩니다.
이 두 가지 옵션은 모두 취약합니다.데이터베이스 마이그레이션을 수행하지 않고 열거형이 수정된 경우 데이터의 무결성을 유지할 수 있습니다.
3. 라이프 사이클 콜백
가능한 솔루션으로는 JPA 라이프 사이클 콜백 주석, @PrePersist 및 @PostLoad를 사용할 수 있습니다.엔티티에 두 가지 변수가 있기 때문에 상당히 보기 흉하게 느껴집니다.하나는 데이터베이스에 저장된 값을 매핑하고 다른 하나는 실제 열거형입니다.
4. 열거형별 고유ID 매핑
권장되는 솔루션은 열거형 내에서 정의된 고정값 또는 ID에 열거형을 매핑하는 것입니다.미리 정의된 고정 값에 매핑하면 코드가 더욱 강력해집니다.에넘 유형의 순서를 변경하거나 이름을 리팩터링해도 악영향이 발생하지 않습니다.
5. Java EE7 @Convert 사용
JPA 2.1을 사용하는 경우 새로운 @Convert 주석을 사용할 수 있습니다.이를 위해서는 @Converter로 주석을 단 변환기 클래스를 작성해야 합니다.이 클래스는 각 열거형에 대해 데이터베이스에 저장되는 값을 정의합니다.그런 다음 엔티티 내에서 @Convert를 사용하여 열거형에 주석을 달 수 있습니다.
희망사항 : (4번)
변환기를 사용하는 것보다 열거형 내에서 ID를 정의하는 것을 선호하는 이유는 캡슐화가 양호하기 때문입니다.ID는 열거형만 알고 데이터베이스에 열거형을 매핑하는 방법은 엔티티만 알아야 합니다.
코드의 예에 대해서는, 원래의 투고를 참조해 주세요.
문제는 JPA가 기존의 복잡한 스키마를 이미 가지고 있을 수 있다는 생각에 사로잡힌 적이 없다는 것입니다.
Enum에는 두 가지 주요 결점이 있다고 생각합니다.
- name() 및 서수()를 사용하는 경우의 제한.@Entity에서처럼 @Id로 getter를 표시하면 어떨까요?
- Enum은 보통 데이터베이스에 표현되어 적절한 이름, 설명적인 이름, 현지화 등과 같은 모든 종류의 메타데이터와 연관지을 수 있습니다.Enum의 사용 편의성과 엔티티의 유연성이 결합되어야 합니다.
JPA_SPEC-47에 대한 투표 지원
문제를 해결하기 위해 @Converter를 사용하는 것보다 더 우아하지 않을까요?
// Note: this code won't work!!
// it is just a sample of how I *would* want it to work!
@Enumerated
public enum Language {
ENGLISH_US("en-US"),
ENGLISH_BRITISH("en-BR"),
FRENCH("fr"),
FRENCH_CANADIAN("fr-CA");
@ID
private String code;
@Column(name="DESCRIPTION")
private String description;
Language(String code) {
this.code = code;
}
public String getCode() {
return code;
}
public String getDescription() {
return description;
}
}
이러한 Enum JPA 매핑을 해결하기 위한 나만의 솔루션은 다음과 같습니다.
스텝 1 - db 컬럼에 매핑하는 모든 enum에 사용할 다음 인터페이스를 작성합니다.
public interface IDbValue<T extends java.io.Serializable> {
T getDbVal();
}
스텝 2 - 다음과 같이 커스텀 범용 JPA 컨버터를 실장합니다.
import javax.persistence.AttributeConverter;
public abstract class EnumDbValueConverter<T extends java.io.Serializable, E extends Enum<E> & IDbValue<T>>
implements AttributeConverter<E, T> {
private final Class<E> clazz;
public EnumDbValueConverter(Class<E> clazz){
this.clazz = clazz;
}
@Override
public T convertToDatabaseColumn(E attribute) {
if (attribute == null) {
return null;
}
return attribute.getDbVal();
}
@Override
public E convertToEntityAttribute(T dbData) {
if (dbData == null) {
return null;
}
for (E e : clazz.getEnumConstants()) {
if (dbData.equals(e.getDbVal())) {
return e;
}
}
// handle error as you prefer, for example, using slf4j:
// log.error("Unable to convert {} to enum {}.", dbData, clazz.getCanonicalName());
return null;
}
}
값인 enum 합니다.E
"" " " " " " " " " " " 로 이동T
String
를 하여 설정해 주세요.getDbVal()
E
그도 마찬가지입니다그리고 역도 성립.
스텝 3 - 스텝1에서 정의한 인터페이스를 원래 열거형으로 구현합니다.
public enum Right implements IDbValue<Integer> {
READ(100), WRITE(200), EDITOR (300);
private final Integer dbVal;
private Right(Integer dbVal) {
this.dbVal = dbVal;
}
@Override
public Integer getDbVal() {
return dbVal;
}
}
스텝 4 - 스텝2의 컨버터를 확장하여Right
: 텝 of3 enum enum :
public class RightConverter extends EnumDbValueConverter<Integer, Right> {
public RightConverter() {
super(Right.class);
}
}
5단계 - 마지막 단계는 다음과 같이 엔티티의 필드에 주석을 다는 것입니다.
@Column(name = "RIGHT")
@Convert(converter = RightConverter.class)
private Right right;
결론
IMHO 매핑해야 할 Enum이 많고 Enum 자체의 특정 필드를 매핑 값으로 사용하는 경우 가장 깨끗하고 우아한 솔루션입니다.
프로젝트에서 유사한 매핑 로직이 필요한 다른 모든 enum에 대해서는 3단계부터 5단계까지만 반복하면 됩니다.즉, 다음과 같습니다.
- 를
IDbValue
기입해 주세요. - 을 하다
EnumDbValueConverter
코드 3줄만 사용(분리된 클래스를 만들지 않기 위해 엔티티 내에서 이 작업을 수행할 수도 있습니다). - 에 enum을
@Convert
부터javax.persistence
패키지.
이게 도움이 됐으면 좋겠다.
Pascal 관련 코드 닫기
@Entity
@Table(name = "AUTHORITY_")
public class Authority implements Serializable {
public enum Right {
READ(100), WRITE(200), EDITOR(300);
private Integer value;
private Right(Integer value) {
this.value = value;
}
// Reverse lookup Right for getting a Key from it's values
private static final Map<Integer, Right> lookup = new HashMap<Integer, Right>();
static {
for (Right item : Right.values())
lookup.put(item.getValue(), item);
}
public Integer getValue() {
return value;
}
public static Right getKey(Integer value) {
return lookup.get(value);
}
};
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "AUTHORITY_ID")
private Long id;
@Column(name = "RIGHT_ID")
private Integer rightId;
public Right getRight() {
return Right.getKey(this.rightId);
}
public void setRight(Right right) {
this.rightId = right.getValue();
}
}
나는 다음과 같이 할 것이다.
자체 파일에서 열거형을 따로 선언합니다.
public enum RightEnum {
READ(100), WRITE(200), EDITOR (300);
private int value;
private RightEnum (int value) { this.value = value; }
@Override
public static Etapa valueOf(Integer value){
for( RightEnum r : RightEnum .values() ){
if ( r.getValue().equals(value))
return r;
}
return null;//or throw exception
}
public int getValue() { return value; }
}
Right라는 이름의 새 JPA 엔티티를 선언합니다.
@Entity
public class Right{
@Id
private Integer id;
//FIElDS
// constructor
public Right(RightEnum rightEnum){
this.id = rightEnum.getValue();
}
public Right getInstance(RightEnum rightEnum){
return new Right(rightEnum);
}
}
이 값을 수신하기 위해서도 변환기가 필요합니다(JPA 2.1에만 해당하며, 변환기를 사용하여 직접 유지되는 문제가 있으므로 여기서 설명하지 않습니다).
import mypackage.RightEnum;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
/**
*
*
*/
@Converter(autoApply = true)
public class RightEnumConverter implements AttributeConverter<RightEnum, Integer>{
@Override //this method shoudn´t be used, but I implemented anyway, just in case
public Integer convertToDatabaseColumn(RightEnum attribute) {
return attribute.getValue();
}
@Override
public RightEnum convertToEntityAttribute(Integer dbData) {
return RightEnum.valueOf(dbData);
}
}
Authority 엔티티:
@Entity
@Table(name = "AUTHORITY_")
public class Authority implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "AUTHORITY_ID")
private Long id;
// the **Entity** to map :
private Right right;
// the **Enum** to map (not to be persisted or updated) :
@Column(name="COLUMN1", insertable = false, updatable = false)
@Convert(converter = RightEnumConverter.class)
private RightEnum rightEnum;
}
이렇게 하면 열거 필드에 직접 설정할 수 없습니다.그러나 다음 명령을 사용하여 권한의 오른쪽 필드를 설정할 수 있습니다.
autorithy.setRight( Right.getInstance( RightEnum.READ ) );//for example
비교가 필요한 경우 다음을 사용할 수 있습니다.
authority.getRight().equals( RightEnum.READ ); //for example
꽤 멋진 것 같아요이 변환기는 열거와 함께 사용할 의도가 없기 때문에 완전히 정확하지는 않습니다.실제로 문서에는 이 목적을 위해 이 주석을 사용하지 말고 @Enumerated 주석을 사용해야 한다고 나와 있습니다.문제는 ORDINAL과 STRING의 두 가지 열거형만 존재하지만 ORDINAL은 까다롭고 안전하지 않다는 것입니다.
하지만, 만약 그것이 당신을 만족시키지 못한다면, 당신은 조금 더 교묘하고 간단한 것을 할 수 있다.
어디 보자.
오른쪽 Enum:
public enum RightEnum {
READ(100), WRITE(200), EDITOR (300);
private int value;
private RightEnum (int value) {
try {
this.value= value;
final Field field = this.getClass().getSuperclass().getDeclaredField("ordinal");
field.setAccessible(true);
field.set(this, value);
} catch (Exception e) {//or use more multicatch if you use JDK 1.7+
throw new RuntimeException(e);
}
}
@Override
public static Etapa valueOf(Integer value){
for( RightEnum r : RightEnum .values() ){
if ( r.getValue().equals(value))
return r;
}
return null;//or throw exception
}
public int getValue() { return value; }
}
및 인증국 엔티티
@Entity
@Table(name = "AUTHORITY_")
public class Authority implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "AUTHORITY_ID")
private Long id;
// the **Enum** to map (to be persisted or updated) :
@Column(name="COLUMN1")
@Enumerated(EnumType.ORDINAL)
private RightEnum rightEnum;
}
이 두 번째 아이디어에서는 순서 속성을 해킹한 이후로는 완벽한 상황은 아니지만 훨씬 더 작은 코딩입니다.
JPA 사양에는 Enum Type이 포함되어 있어야 한다고 생각합니다.enum value 필드에 일종의 @EnumId 주석을 붙여야 하는 ID.
언급URL : https://stackoverflow.com/questions/2751733/map-enum-in-jpa-with-fixed-values
'sourcecode' 카테고리의 다른 글
개발 모드에서 이 HTML 템플릿을 컴파일하는 데 Vue가 매우 느림 (0) | 2022.07.17 |
---|---|
스프링 컨트롤러에서 파일 다운로드 (0) | 2022.07.17 |
vue.timeout의 구성 요소에 개체 배열 전달 (0) | 2022.07.17 |
컬렉션을 목록으로 변환하는 방법 (0) | 2022.07.17 |
"2i;"라는 문장이 컴파일러 오류를 일으키지 않는 이유는 무엇입니까? (0) | 2022.07.17 |