java - 将 ENUM 值存储到数据库中
问题描述
我想使用 ENUM 将值映射到数据库表行:
业务客户搜索参数:
@Getter
@Setter
public class BusinessCustomersSearchParams {
private String title;
private List<String> status;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
规格:
@Override
public Page<BusinessCustomersFullDTO> findBusinessCustomers(BusinessCustomersSearchParams params, Pageable pageable)
{
Specification<BusinessCustomers> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (params.getTitle() != null) {
predicates.add(cb.like(cb.lower(root.get("description")), "%" + params.getTitle().toLowerCase() + "%"));
}
final List<String> statuses = Optional.ofNullable(params.getStatus()).orElse(Collections.emptyList());
if (statuses != null && !statuses.isEmpty()){
List<BusinessCustomersStatus> statusesAsEnum = statuses.stream()
.map(status -> BusinessCustomersStatus.fromStatus(status))
.collect(Collectors.toList())
;
predicates.add(root.get("status").in(statusesAsEnum));
}
return cb.and(predicates.toArray(new Predicate[predicates.size()]));
};
return businessCustomersService.findAll(spec, pageable).map(businessCustomersMapper::toFullDTO);
}
属性转换器:
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
@Converter
public class BusinessCustomersStatusAttributeConverter
implements AttributeConverter<BusinessCustomersStatus, String> {
public String convertToDatabaseColumn( BusinessCustomersStatus value ) {
if ( value == null ) {
return null;
}
return value.getStatus();
}
public BusinessCustomersStatus convertToEntityAttribute( String value ) {
if ( value == null ) {
return null;
}
return BusinessCustomersStatus.fromStatus( value );
}
}
枚举:
package org.merchant.database.service.businesscustomers;
public enum BusinessCustomersStatus {
A("active"),
O("onboarding"),
N("not_verified"),
V("verified"),
S("suspended"),
I("inactive");
private String status;
BusinessCustomersStatus(String status)
{
this.status = status;
}
public String getStatus() {
return status;
}
public static BusinessCustomersStatus fromStatus(String status) {
switch (status) {
case "active": {
return A;
}
case "onboarding": {
return O;
}
case "not_verified": {
return NV;
}
case "verified": {
return V;
}
case "suspended": {
return S;
}
case "inactive": {
return I;
}
default: {
throw new UnsupportedOperationException(
String.format("Unkhown status: '%s'", status)
);
}
}
}
}
实体:
@Entity
@Table(name = "business_customers")
public class BusinessCustomers implements Serializable {
..........
@Convert( converter = BusinessCustomersStatusAttributeConverter.class )
private BusinessCustomersStatus status;
......
}
完整代码示例:https ://github.com/rcbandit111/Search_specification_POC
我发送带有参数的 http 查询,list?size=5&page=0&status=active,suspended
得到的结果是大写字母“status”:“ACTIVE”。
我想从 FE 中搜索并获取状态以获取状态,status=active
但仅将符号 A 存储到数据库行字段中。
如何将 ENUM 键 A 存储到数据库中?
解决方案
为了在数据库中存储实际的枚举值,您可以做两件事。
一,正如@PetarBivolarski 所建议的那样,修改方法convertToDatabaseColumn
并AttributeConverter
返回value.name()
而不是value.getStatus()
. 但是请注意,此外,您还需要更新convertToEntityAttribute
以考虑该更改:
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
@Converter
public class BusinessCustomersStatusAttributeConverter
implements AttributeConverter<BusinessCustomersStatus, String> {
public String convertToDatabaseColumn( BusinessCustomersStatus value ) {
if ( value == null ) {
return null;
}
return value.name();
}
public BusinessCustomersStatus convertToEntityAttribute( String value ) {
if ( value == null ) {
return null;
}
return BusinessCustomersStatus.valueOf( value );
}
}
如果您考虑一下,更直接的解决方案是将status
字段保留为@Enumerated
:
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
@Entity
@Table(name = "business_customers")
public class BusinessCustomers {
//...
@Enumerated(EnumType.STRING)
@Column(name = "status", length = 20)
private BusinessCustomersStatus status;
//...
}
根据您的代码的其余部分,它还更多。
关于您的第二个问题,应用程序正在返回"status":"ACTIVE"
,因为BusinessCustomersFullDTO
您将状态字段定义为,String
并且该字段接收由and执行的映射过程的结果。@Mapstruct
BusinessCustomersMapper
为了解决这个问题,正如我之前建议的那样,您可以修改您的Mapper
以处理所需的自定义转换:
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
import org.merchant.config.BaseMapperConfig;
import org.merchant.database.entity.BusinessCustomers;
import org.merchant.database.service.businesscustomers.BusinessCustomersStatus;
import org.merchant.dto.businesscustomers.BusinessCustomersFullDTO;
@Mapper(config = BaseMapperConfig.class)
public interface BusinessCustomersMapper {
@Mapping(source = "status", target = "status", qualifiedByName = "businessCustomersToDTOStatus")
BusinessCustomersFullDTO toFullDTO(BusinessCustomers businessCustomers);
@Named("busineessCustomersToDTOStatus")
public static String businessCustomersToDTOStatus(final BusinessCustomersStatus status) {
if (status == null) {
return null;
}
return status.getStatus();
}
}
如果您不喜欢此解决方案,也许您可以采取不同的方法:它将包括以下内容。这个想法是修改杰克逊的序列化和反序列化行为BusinessCustomersFullDTO
。事实上,在你的用例中只需要修改序列化逻辑。
首先,根据以下内容定义status
字段:BusinessCustomersFullDTO
BusinessCustomersStatus
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder(toBuilder = true)
public class BusinessCustomersFullDTO {
private long id;
private String name;
private String businessType;
private BusinessCustomersStatus status;
private String description;
private String country;
private String address1;
}
要完成解决方案,请在BusinessCustomersStatus
枚举中执行以下更改:
public enum BusinessCustomersStatus {
A("active"),
O("onboarding"),
NV("not_verified"),
V("verified"),
S("suspended"),
I("inactive");
private String status;
BusinessCustomersStatus(String status)
{
this.status = status;
}
// Define the status field as the enum representation by using @JsonValue
@JsonValue
public String getStatus() {
return status;
}
// Use the fromStatus method as @JsonCreator
@JsonCreator
public static BusinessCustomersStatus fromStatus(String status) {
if (StringUtils.isEmpty(status)) {
return null;
}
switch (status) {
case "active": {
return A;
}
case "onboarding": {
return O;
}
case "not_verified": {
return NV;
}
case "verified": {
return V;
}
case "suspended": {
return S;
}
case "inactive": {
return I;
}
default: {
throw new UnsupportedOperationException(
String.format("Unkhown status: '%s'", status)
);
}
}
}
}
请注意包含@JsonValue
和@JsonCreator
注释:后者用于反序列化,这在您的应用程序中对我来说似乎是不必要的,但以防万一。
请参阅提供的 Jackson 注释的相关文档。
推荐阅读
- linux - 将 ZFS 快照应用到非 ZFS FS
- proxy - Kubernetes 和 Prometheus 不与 Grafana 一起工作
- java - 如何通过拖动鼠标/手指来移动身体/演员?
- android - 按值的日期属性对 Hashmap 键进行排序
- python - IndexError: 元组索引超出范围 --- Python
- vb.net - 根据数据集值在 windows 窗体上创建阈值
- html - Bootstrap 4 Grid - 行的长度不同
- python - 运行 def __init__(self) 函数后,如何在类对象中添加数据?
- java - 删除多对一关系中删除父级的子级
- java - 如何在窗口中显示变化的整数?