【问题标题】:Control sort order of Hibernate EnumType.STRING properties控制 Hibernate EnumType.STRING 属性的排序顺序
【发布时间】:2011-04-06 01:27:28
【问题描述】:

目前,我的项目使用@Enumerated(EnumType.ORDINAL),所以当我按此列排序时,它是根据enum中的顺序排序的,效果很好。但是我需要在enum 中添加一些额外的值,这些值需要插入到枚举值列表中的不同位置,并且不能仅仅添加到底部以保持正确的排序顺序。

如果我这样做,我的数据库就会被弄乱。我将不得不编写一些脚本来将所有这些序数值转换为正确的新序数。以后可能需要添加更多状态。由于我必须修复数据库中的所有数据,因此我只想做一次,因为这将是一项艰巨的任务。

所以我正在考虑切换到 EnumType.STRING 以不必再次重新映射数据库中的序数值。但是如果我这样做,那么我该如何正确排序呢?枚举字符串的字母顺序不是我需要的顺序。

使用下面的类,当我按属性“状态”排序时,结果按以下顺序出现:

hql = "from Project order by status"

Development
Planning
Production

我希望他们按这个顺序出来,不使用EnumType.ORDINAL

Planning
Development
Production

如果不为enum 创建表或向Project 类添加额外的列,这是否可行?我试过了,但它抛出了一个异常:

hql = "from Project order by status.sort"

枚举:

public enum Status {

    PLANNING("Planning", 0),
    DEVELOPMENT("Development", 1),
    PRODUCTION("Production", 2);

    private final String name;
    private final int sort;
    private Status(String name, int sort) {
        this.name = name;
        this.sort = sort;
    }
    @Override
    public String toString() {
        return name;
    }
}

实体:

@Entity
public class Project {
    private Long id;
    private Status status;

    @Id
    @GeneratedValue
    public Long getId() {
        return this.id;
    }
    private void setId(Long id) {
        this.id = id;
    }
    @Enumerated(EnumType.STRING)
    public Status getStatus() {
        return status;
    }
    public void setStatus(Status status) {
        this.status = status;
    }
}

【问题讨论】:

    标签: java hibernate orm enums hql


    【解决方案1】:

    所以我正在考虑切换到 EnumType.STRING 以不必再次重新映射数据库中的序数值。但是如果我这样做,那么我该如何正确排序呢?枚举字符串的字母顺序不是我需要的顺序。

    我个人完全避免使用邪恶的EnumType.ORDINAL,因为仅仅改变常量的顺序会破坏持久性逻辑。邪恶。也就是说,EnumType.STRING 确实并不总是合适的。

    在您的情况下,这就是我要做的(使用标准 JPA):我将在实体级别保留 int 并在 getter/setter 中执行枚举转换。像这样的东西。一、枚举:

    public enum Status {
        PLANNING("Planning", 100),
        DEVELOPMENT("Development", 200),
        PRODUCTION("Production", 300);
    
        private final String label;
        private final int code;
    
        private Status(String label, int code) {
            this.label = label;
            this.code = code;
        }
    
        public int getCode() { return this.code; }
    
        private static final Map<Integer,Status> map;
        static {
            map = new HashMap<Integer,Status>();
            for (Status v : Status.values()) {
                map.put(v.code, v);
            }
        }
        public static Status parse(int i) {
            return map.get(i);
        }
    }
    

    所以基本上,这个想法是能够通过其code 获得Status。而且我们在常量之间保留了一些空间,以便可以添加值(这并不漂亮,但是,它会起作用并且应该在一段时间内是安全的)。

    然后在实体中:

    @Entity
    public class Project {
        private Long id;
        private int statusCode;
    
        @Id @GeneratedValue
        public Long getId() {
            return this.id;
        }
        private void setId(Long id) {
            this.id = id;
        }
    
        @Transient
        public Status getStatus () {
            return Status.parse(this.statusCode);
        }
        public void setStatus(Status status) {
            this.statusCode = status.getCode();
        }
    
        protected int getStatusCode() {
            return statusCode;
        }
        protected void setStatusCode(int statusCode) {
            this.statusCode = statusCode;
        }
    }
    

    int 表示的 getter/setter 受到保护。公共 getter/setter 处理转换。

    另一种解决方案是使用自定义类型(以可移植性为代价)。

    相关问题

    【讨论】:

    • @Pascal:非常好,这正是我所希望的解决方案。我的问题似乎需要一点破解,而您的“破解”似乎尽可能优雅。我会试一试。谢谢!
    • @Pascal:完美运行!当然,我必须更改我的查询以使用 Status.PLANNING.getCode() 之类的值而不是 statusStatus.PLANNING 来引用属性 statusCode
    • 为什么EnumType.ORDINAL是邪恶的?它很小,速度很快。好的,您(真的)不应该更改枚举声明中的顺序,但文件中的注释会这样做。 EnumType.STRING 有同样的缺陷,你不能改变枚举的名字。这两种方法都有其问题。
    • 当您添加新的枚举值时,此技术可以正常工作,但它不会让您重新排序现有值。它还需要重新映射数据库以使用新代码。那么保持原样,然后实现 Comparator&lt;Status&gt; 类不是更好吗?
    • @Will 每次我使用ORDINAL 时都会回来咬我,这又是一个例子。如果我使用了STRING,至少它不需要数据库更新。我发现我更有可能需要在枚举中添加或删除元素,而不是重命名它们。 @Pascal 的解决方案可能并不适合所有人,但它非常适合我的情况。
    猜你喜欢
    • 1970-01-01
    • 2017-10-16
    • 1970-01-01
    • 2014-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-18
    相关资源
    最近更新 更多