控制Hibernate EnumType.STRING属性的排序顺序

时间:2010-08-31 02:28:16

标签: java hibernate orm enums hql

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

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

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

使用下面的类,当我按属性“status”排序时,结果按此顺序排列:

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;
    }
}

1 个答案:

答案 0 :(得分:7)

  

所以我想切换到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);
    }
}

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

然后在实体中:

@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处理转换。

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

相关问题