You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Hibernate读取数组中存储为缩写的枚举集合

解决方案:映射PostgreSQL char(3)[]数组到Set

要解决Hibernate对数组存储的枚举缩写集合的双向转换问题,需要实现针对集合类型的AttributeConverter,并配合Hibernate的数组类型映射,具体步骤如下:

1. 实现集合转换器

创建AttributeConverter,负责Set<DayOfWeek>与数据库char(3)[]对应的String[]之间的双向转换:

import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.time.DayOfWeek;

@Converter(autoApply = false)
public class DayOfWeekSetConverter implements AttributeConverter<Set<DayOfWeek>, String[]> {

    // 枚举与数据库缩写的映射关系
    private static final Map<DayOfWeek, String> DAY_TO_ABBR = Map.of(
        DayOfWeek.MONDAY, "mon",
        DayOfWeek.TUESDAY, "tue",
        DayOfWeek.WEDNESDAY, "wed",
        DayOfWeek.THURSDAY, "thu",
        DayOfWeek.FRIDAY, "fri",
        DayOfWeek.SATURDAY, "sat",
        DayOfWeek.SUNDAY, "sun"
    );

    private static final Map<String, DayOfWeek> ABBR_TO_DAY = DAY_TO_ABBR.entrySet()
        .stream()
        .collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));

    @Override
    public String[] convertToDatabaseColumn(Set<DayOfWeek> days) {
        if (days == null || days.isEmpty()) {
            return null;
        }
        return days.stream()
            .map(DAY_TO_ABBR::get)
            .toArray(String[]::new);
    }

    @Override
    public Set<DayOfWeek> convertToEntityAttribute(String[] dbAbbrs) {
        if (dbAbbrs == null || dbAbbrs.length == 0) {
            return Collections.emptySet();
        }
        return Arrays.stream(dbAbbrs)
            .map(ABBR_TO_DAY::get)
            .collect(Collectors.toSet());
    }
}

2. 配置实体类属性

在Schedule实体的daysOfWeek属性上,同时添加三个注解:

  • @Column:指定数据库列类型为char(3)[]
  • @Type:指定Hibernate的数组类型处理器ArrayType
  • @Convert:关联上面实现的集合转换器
import java.time.DayOfWeek;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Convert;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import org.hibernate.annotations.Type;

@Entity
@Table(name = "schedule")
public class Schedule {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // 其他属性...

    @Column(name = "days_of_week", columnDefinition = "char(3)[]")
    @Type(type = "org.hibernate.type.ArrayType")
    @Convert(converter = DayOfWeekSetConverter.class)
    private Set<DayOfWeek> daysOfWeek;

    // Getter、Setter方法...
}

关键说明

  • 为什么之前的方法失效?
    • 直接映射:Hibernate无默认规则将数据库数组转换为枚举集合,抛出类型转换异常
    • @Enumerated(EnumType.STRING):枚举默认名称(如MONDAY)与数据库缩写(mon)不匹配,无法映射
    • 单个枚举转换器:仅支持单个DayOfWeek与缩写的转换,无法直接作用于Set集合
    • @ElementCollection:用于将集合映射到关联表,而非数据库原生数组列,不符合需求
  • 注意事项:确保数据库中存储的缩写与转换器中的映射完全一致(大小写、长度),避免转换失败
  • 兼容性:Hibernate的ArrayType支持PostgreSQL等原生数组类型的数据库,无需额外依赖

内容的提问来源于stack exchange,提问作者danissimo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 00:50:21