繁体   English   中英

将 ENUM 值存储到数据库中

[英]Store ENUM value into database

我想使用 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

我发送带有 params list?size=5&page=0&status=active,suspended http 查询,结果得到大写字母“status”:“ACTIVE”。

我想使用status=active从 FE 搜索并获取状态的状态,但仅将符号 A 存储到数据库行字段中。

如何将 ENUM 键 A 存储到数据库中?

为了在数据库中存储实际的枚举值,您可以做两件事。

一,按照@PetarBivolarski 的建议,修改AttributeConverter convertToDatabaseColumn方法并返回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并且该字段接收由@MapstructBusinessCustomersMapper执行的映射过程的结果。

为了解决这个问题,正如我之前建议你的,你可以修改你的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的 Jackson 序列化和反序列化行为。 实际上,在您的用例中只需要修改序列化逻辑。

首先,定义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 注释的相关文档

注意BusinessCustomersStatusAttributeConverter convertToDatabaseColumn()方法。

它应该返回value.name()而不是value.getStatus()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM