是否可以在不为实体创建新表的情况下将HashSet<DayOfWeek>添加到实体?我想把它存储为json.

@Entity
@Table(name="test")
public class Test{

    @Id
    @GeneratedValue
    private Long id;

    @Enumerated(EnumType.STRING)
    @Column(columnDefinition = "json")
    private HashSet<DayOfWeek> activeDays;
}

推荐答案

简单值的集合可以用@ElementCollection来映射,但这需要一个单独的表.

对于问题的情况,即将一组枚举映射到单个列,我喜欢使用位集-就像Java的EnumSet在幕后所做的那样.我们将枚举的每个成员映射到只有1位集的布尔值,例如:

Enum member boolean
MONDAY 0000001
TUESDAY 0000010
WEDNESDAY 0000100
...and so on 0001000

将枚举映射到位集只需1 << dayOfWeek.ordinal().因此,例如,值0000EnumSet.of(WEDNESDAY, MONDAY)表示EnumSet.of(WEDNESDAY, MONDAY).现在可以很容易地使用数据库的位运算符来查询成员资格-例如,如果您想要包含TUESDAY的所有Test条记录,请执行以下操作:

-- This is a pseudocode example!!!
-- Various DBs have different ways to express binary constants and bitwise operators
SELECT * FROM Test WHERE activeDays & 0b0000010 <> 0

这需要JPA AttributeConverter,如下所示:

import javax.persistence.AttributeConverter;
import java.time.DayOfWeek;
import java.util.AbstractCollection;
import java.util.Arrays;
import java.util.EnumSet;

public class DayOfWeekConverter implements AttributeConverter<EnumSet<DayOfWeek>, Integer> {
    @Override
    public Integer convertToDatabaseColumn(EnumSet<DayOfWeek> value) {
        return value == null ? null : value.stream().mapToInt(this::toBitmap).reduce(0, (aggr, cur) -> aggr | cur);
    }

    private int toBitmap(DayOfWeek d) {
        return 1 << d.ordinal();
    }

    @Override
    public EnumSet<DayOfWeek> convertToEntityAttribute(Integer dbData) {
        return dbData == null ? null :
                Arrays.stream(DayOfWeek.values())
                        .filter(d -> (toBitmap(d) & dbData) != 0)
                        .collect(
                                () -> EnumSet.noneOf(DayOfWeek.class),
                                AbstractCollection::add,
                                AbstractCollection::addAll
                        );
    }
}

...和字段上的注释,如下所示-请注意,我使用了效率更高的EnumSet作为数据类型:

@Convert(converter = DayOfWeekConverter.class)
private EnumSet<DayOfWeek> activeDays;

您可以调整转换器以存储JSON值或您能想到的EnumSet的任何自定义格式(例如,像"|MONDAY|WEDNESDAY|"这样的字符串是完全可能的,并且是可查询的,例如activeDays LIKE '%|MONDAY|%').我认为如果使用字符串表示,通过SQL进行搜索的效率会较低,但这取决于您.

实际上,如上所述的字符串转换器可以实现为:

public class DayOfWeekConverter implements AttributeConverter<EnumSet<DayOfWeek>, String> {
    @Override
    public String convertToDatabaseColumn(EnumSet<DayOfWeek> value) {
        return value == null ? null : value.stream().map(Enum::name).collect(Collectors.joining("|","|","|"));
    }

    @Override
    public EnumSet<DayOfWeek> convertToEntityAttribute(String dbData) {
        return dbData == null ? null :
                Arrays.stream(DayOfWeek.values())
                        .filter(d -> dbData.contains('|' + d.name() + '|'))
                        .collect(
                                () -> EnumSet.noneOf(DayOfWeek.class),
                                AbstractCollection::add,
                                AbstractCollection::addAll
                        );
    }
}

Java相关问答推荐

如何使用CSS为选定但未聚焦的表格行设置背景 colored颜色 ?

Annotation @ Memphier无法正常工作,并表示:class需要一个bean,但找到了2个bean:

如何将kotlin代码转换为java

如何在SystemiccationRetryListenerSupport中获得类级别的spring retryable annotation中指定的标签?

如果一个子类没有构造函数,超类也没有构造函数,那么为什么我可以构造子类的实例呢?

CAMEL 4中的SAXParseException

通过合并Akka Streams中的多个慢源保持订购

Java 21 struct 化连接货币,需要可预知的子任务异常排序

FALSE:它应该在什么时候使用?

蒙蒂霍尔比赛结果不正确

SpringBoot+Java 17@Valid未验证POJO

将带有js文件的 bootstrap 程序导入maven项目时出错

如何对多个字段进行分组和排序?

使用Jackson库反序列化json

IntelliJ IDEA依赖项工具窗口丢失

从泛型枚举创建EnumMap

如何在ImageIO或十二只猴子中旋转TIFF CMYK图像?

为什么Instant没有从UTC转换为PostgreSQL的时区?

错误:JOIN/ON的参数必须是boolean类型,而不是bigint类型.Java Spring启动应用程序

简化每个元素本身都是 map 列表的列表