# [Spring Data JPA] 在實體類(Entity)轉換 Enum 屬性 [TOC] 假設有個 Order 實體類中的屬性 status,資料中的數字有其意義,如: 1=訂單成功,2=待付款,3=待出貨,4=待收貨,5=訂單已完成,-1=訂單不成立,-2=退貨退款。 ```=java! @RequiredArgsConstructor @Getter public enum OrderStatus { SUCCESS(1), PAYMENT(2), SHIPMENT(3), COLLECT(4), COMPLETE(5), CANCEL(-1), SEND_BACK(-2); private final Integer id; } ``` ## 方式一: getter getter的時候做判斷和轉換。 ```=java! @Entity @Data public class Order { @Column(name = "status") private Integer status; private OrderStatus getStatus(){ return Arrays.stream(OrderStatus.values()) .filter(e -> e.getId() == status) .findFirst() .orElseThrow(() -> new UnsupportedOperationException( String.format("找不到與 %s 對應的狀態", status))); } } ``` ## 方式二: @Enumerated 交由 JPA 轉換。JPA 會直接依 enum 的順序寫入 status 的值,在 `find` 的時候也是用順序轉換成對應的 enum,如 SUCCESS 會寫入0,1會取出 OrderStatus.PAYMENT。 ```=java! @Entity @Data public class Order { @Column(name = "status") private OrderStatus status; } ``` 但有時候需要儲存的是 Enum name,這時只需要增加 annotation 即可用 Enum name 來轉換。 * `EnumType` Enum name 的型態 * `ORDINAL` 數字 * `STRING` 字串 ```=java! @Entity @Data public class Order { @Column(name = "status") @Enumerated(EnumType.STRING) private OrderStatus status; } ``` ## 方式三: 轉換器 Convert 還有一種情況是實際需要的是 Enum 的 value,這時可以建立轉換器自行定義,此方法也較彈性。 ### 範例 1. 假設現在 OrderStatus 有多個 value ```=java! @RequiredArgsConstructor @Getter public enum OrderStatus { SUCCESS(1, "訂單成功"), PAYMENT(2, "待付款"), SHIPMENT(3, "待出貨"), COLLECT(4, "待收貨"), COMPLETE(5, "訂單已完成"), CANCEL(-1, "訂單不成立"), SEND_BACK(-2, "退貨退款"); private final Integer id; private final String desc; } ``` 2. 建立轉換器 * 需加上 `@Converter` 註釋 * 實作介面 `AttributeConverter.class` ```=java! import javax.persistence.AttributeConverter; import javax.persistence.Converter; @Converter public class OrderStatusConverter implements AttributeConverter<OrderStatus, Integer>{ @Override public Integer convertToDatabaseColumn(OrderStatus orderStatus) { return OrderStatus.getId(); } @Override public OrderStatus convertToEntityAttribute(Integer id) { return Arrays.stream(OrderStatus.values()) .filter(orderStatus -> OrderStatus.getId() == id) .findFirst() .orElseThrow(() -> new UnsupportedOperationException( String.format("找不到 id = %s 對應的 OrderStatus", id))); } } ``` 3. 加上註釋 `@Convert` ,讓 JPA 使用指定的轉換器 ```=java! @Entity @Data public class Order { @Column(name = "status") @Convert(converter = OrderStatusConverter.class) private OrderStatus status; } ``` 參考資料: [Spring Data Custom Converter](https://medium.com/@dvvivek/spring-data-custom-converter-f73e66297098) [Custom Conversions](https://docs.spring.io/spring-data/jpa/reference/data-commons/custom-conversions.html)