# [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)