[SPRING] 고정 값으로 JPA의 enum을 매핑 하시겠습니까?
SPRING고정 값으로 JPA의 enum을 매핑 하시겠습니까?
JPA를 사용하여 열거 형을 매핑하는 여러 가지 방법을 찾고 있습니다. 나는 특히 각 enum 항목의 정수 값을 설정하고 정수 값만 저장하려고합니다.
@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.ORDINAL과 함께 열거 주석을 사용하는 것입니다.
@Column(name = "RIGHT")
@Enumerated(EnumType.ORDINAL)
private Right right;
그러나이 경우 JPA는 열거 형 인덱스 (0,1,2)를 매핑하고 원하는 값 (100,200,300)을 매핑하지 않습니다.
내가 찾은 두 가지 해결책은 단순하지 않은 것 같습니다 ...
여기에 제안 된 솔루션은 @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에 존재하는지 여부는 알 수 없습니다.
해결법
-
==============================
1.JPA 2.1보다 이전 버전의 경우 JPA는 열거 형, 이름 또는 서수를 처리하는 두 가지 방법 만 제공합니다. 그리고 표준 JPA는 사용자 정의 유형을 지원하지 않습니다. 그래서:
JPA 2.1보다 이전 버전의 경우 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; } 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(); } }
-
==============================
2.이것은 JPA 2.1에서 이제 가능합니다 :
이것은 JPA 2.1에서 이제 가능합니다 :
@Column(name = "RIGHT") @Enumerated(EnumType.STRING) private Right right;
추가 세부 정보 :
-
==============================
3.가장 좋은 방법은 각 열거 형에 고유 한 ID를 매핑하여 ORDINAL 및 STRING의 함정을 피하는 것입니다. 열거 형을 매핑 할 수있는 5 가지 방법을 설명하는이 게시물을 참조하십시오.
가장 좋은 방법은 각 열거 형에 고유 한 ID를 매핑하여 ORDINAL 및 STRING의 함정을 피하는 것입니다. 열거 형을 매핑 할 수있는 5 가지 방법을 설명하는이 게시물을 참조하십시오.
위의 링크에서 가져온 것 :
1 & 2. @Enumerated 사용하기
현재 @Enumerated 주석을 사용하여 JPA 엔티티 내에서 enum을 매핑 할 수있는 두 가지 방법이 있습니다. 불행히도 EnumType.STRING과 EnumType.ORDINAL에는 모두 한계가 있습니다.
EnumType.String을 사용하면 열거 형 중 하나의 이름을 바꾸면 열거 형 값이 데이터베이스에 저장된 값과 일치하지 않게됩니다. EnumType.ORDINAL을 사용하면 enum 내에서 유형을 삭제하거나 순서를 변경하면 데이터베이스에 저장된 값이 잘못된 enum 유형으로 매핑됩니다.
이 두 옵션 모두 허약합니다. 데이터베이스 이주를 수행하지 않고 열거 형을 수정하면 데이터 + 결성을 위] 할 수 있습니다.
3. 라이프 사이클 콜백
JPA 수명주기 콜백 주석 인 @PrePersist 및 @PostLoad를 사용하는 것이 해결책입니다. 이는 엔티티에 두 개의 변수가 생기므로 상당히 추한 느낌입니다. 하나는 데이터베이스에 저장된 값을 매핑하고 다른 하나는 실제 열거 형을 매핑합니다.
4. 각 열거 형에 고유 ID 매핑
권장되는 솔루션은 열거 형 내에 정의 된 고정 값 또는 ID로 열거 형을 매핑하는 것입니다. 사전 정의 된 고정 값에 매핑하면 코드가 더욱 강력 해집니다. enums 형식의 순서를 수정하거나 이름을 리팩토링해도 부작용이 발생하지 않습니다.
5. Java EE7 사용하기 @Convert
JPA 2.1을 사용하는 경우 새 @Convert 주석을 사용할 수 있습니다. 이를 위해서는 각 열거 형에 대해 데이터베이스에 저장되는 값을 정의 할 수있는 @Converter 주석이 붙은 변환기 클래스를 만들어야합니다. 엔티티 내에서 열거 형에 @Convert 주석을 추가합니다.
내 취향 : (4 번)
변환기 사용에 반대하는 enum 내에서 내 ID를 정의하는 것을 선호하는 이유는 좋은 캡슐화입니다. enum 타입 만이 그것의 ID를 알고 있어야하고 엔티티 만 enum을 데이터베이스로 매핑하는 방법을 알아야한다.
코드 예제의 원래 게시물을 참조하십시오.
-
==============================
4.문제는 JPA가 이미 기존의 복잡한 스키마를 가질 수 있다는 생각을 결코 받아들이지 않는다는 것입니다.
문제는 JPA가 이미 기존의 복잡한 스키마를 가질 수 있다는 생각을 결코 받아들이지 않는다는 것입니다.
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; } }
-
==============================
5.JPA 2.1에서 AttributeConverter를 사용할 수 있습니다.
JPA 2.1에서 AttributeConverter를 사용할 수 있습니다.
다음과 같이 열거 형 클래스를 작성하십시오.
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 : 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)를 추가 할 수 있습니다.
-
==============================
6.파스칼의 관련 코드를 닫을 가능성이 있음
파스칼의 관련 코드를 닫을 가능성이 있음
@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(); } }
-
==============================
7.나는 다음을 할 것이다 :
나는 다음을 할 것이다 :
자체 파일에 열거 형을 별도로 선언하십시오.
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); } }
권한 기관 :
@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
어느 것이 꽤 멋지다 고 생각합니다. 변환기가 enum과 함께 사용되지 않기 때문에 완전히 정확하지는 않습니다. 실제로,이 목적으로 사용하지 말라는 문서에는 대신 @Enumerated 주석을 사용해야합니다. 문제는 ORDINAL 또는 STRING의 두 가지 열거 유형 만 있지만 ORDINAL은 까다 롭고 안전하지 않다는 것입니다.
그러나, 그것이 당신을 만족시키지 않는다면, 당신은 좀 더 해커하고 더 단순한 (또는하지 않는) 것을 할 수 있습니다.
보자.
RightEnum :
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 값 필드에 @EnumId 주석과 함께 주석을 달아야하는 EnumType.ID가 포함되어야한다고 생각합니다.
from https://stackoverflow.com/questions/2751733/map-enum-in-jpa-with-fixed-values by cc-by-sa and MIT license
'SPRING' 카테고리의 다른 글
[SPRING] 독립 실행 형 Java 응용 프로그램에서 Spring 3 자동 배선 사용 (0) | 2018.12.06 |
---|---|
[SPRING] util 스키마를 사용하여리스트를 자동 배선하는 것은 NoSuchBeanDefinitionException을 준다. (0) | 2018.12.06 |
[SPRING] Spring Framework에서 @Inject와 @Autowired의 차이점은 무엇입니까? 어떤 조건에서 사용할 것인가? (0) | 2018.12.06 |
[SPRING] 봄 MVC + JSON = 406 허용되지 않음 (0) | 2018.12.06 |
[SPRING] Spring Resttemplate 예외 처리 (0) | 2018.12.06 |