一尘不染

在数据库中保存枚举的方法

java

将枚举保存到数据库中的最佳方法是什么?

我知道Java提供name()valueOf()方法来枚举值转换为字符串和背部。但是还有其他(灵活的)选项来存储这些值吗?

有没有一种聪明的方法可以使枚举成为唯一的数字(ordinal()使用不安全)?

更新:

感谢您提供的所有出色且快速的答案!就像我怀疑的那样。

但是要注意“工具包”;那是一种方式。问题是我必须向创建的每个Enum类型添加相同的方法。那就是很多重复的代码,并且目前Java不支持任何解决方案(Java枚举不能扩展其他类)。


阅读 166

收藏
2020-09-08

共1个答案

一尘不染

我们 再也不会 将枚举存储为数字序数值了。这使得调试和支持方式太困难了。我们存储转换为字符串的实际枚举值:

public enum Suit { Spade, Heart, Diamond, Club }

Suit theSuit = Suit.Heart;

szQuery = "INSERT INTO Customers (Name, Suit) " +
          "VALUES ('Ian Boyd', %s)".format(theSuit.name());

然后回读:

Suit theSuit = Suit.valueOf(reader["Suit"]);

该问题过去一直盯着企业管理器并试图破译:

Name                Suit
==================  ==========
Shelby Jackson      2
Ian Boyd            1

经文

Name                Suit
==================  ==========
Shelby Jackson      Diamond
Ian Boyd            Heart

后者要容易得多。前者需要获取源代码并查找分配给枚举成员的数值。

是的,它需要更多的空间,但是枚举成员的名称很短,而硬盘驱动器很便宜,如果遇到问题,可以提供更多帮助。

此外,如果使用数值,则将它们绑定在一起。您不必强制使用旧的数值就无法很好地插入或重新排列成员。例如,将Suit枚举更改为:

public enum Suit { Unknown, Heart, Club, Diamond, Spade }

必须成为:

public enum Suit { 
      Unknown = 4,
      Heart = 1,
      Club = 3,
      Diamond = 2,
      Spade = 0 }

为了维护存储在数据库中的旧数值。

如何在数据库中对它们进行排序

问题来了:可以说我想对值进行排序。有些人可能想按枚举的序数对它们进行排序。当然,按枚举的数值对卡片排序是没有意义的:

SELECT Suit FROM Cards
ORDER BY SuitID; --where SuitID is integer value(4,1,3,2,0)

Suit
------
Spade
Heart
Diamond
Club
Unknown

那不是我们想要的顺序-我们希望它们按枚举顺序:

SELECT Suit FROM Cards
ORDER BY CASE SuitID OF
    WHEN 4 THEN 0 --Unknown first
    WHEN 1 THEN 1 --Heart
    WHEN 3 THEN 2 --Club
    WHEN 2 THEN 3 --Diamond
    WHEN 0 THEN 4 --Spade
    ELSE 999 END

如果保存字符串,则需要执行与保存整数值相同的工作:

SELECT Suit FROM Cards
ORDER BY Suit; --where Suit is an enum name

Suit
-------
Club
Diamond
Heart
Spade
Unknown

但这不是我们想要的顺序-我们希望它们按枚举顺序:

SELECT Suit FROM Cards
ORDER BY CASE Suit OF
    WHEN 'Unknown' THEN 0
    WHEN 'Heart'   THEN 1
    WHEN 'Club'    THEN 2
    WHEN 'Diamond' THEN 3
    WHEN 'Space'   THEN 4
    ELSE 999 END

我认为这种排名属于用户界面。如果您要根据项目的枚举值对项目进行排序:您做错了什么。

但是,如果您想真正做到这一点,我将创建一个Suits尺寸表:

| Suit       | SuitID       | Rank          | Color  |
|------------|--------------|---------------|--------|
| Unknown    | 4            | 0             | NULL   |
| Heart      | 1            | 1             | Red    |
| Club       | 3            | 2             | Black  |
| Diamond    | 2            | 3             | Red    |
| Spade      | 0            | 4             | Black  |

这样,当您想更改卡以使用“ 接吻王”卡牌 定单时 ,可以出于显示目的进行更改,而不会丢弃所有数据:

| Suit       | SuitID       | Rank          | Color  | CardOrder |
|------------|--------------|---------------|--------|-----------|
| Unknown    | 4            | 0             | NULL   | NULL      |
| Spade      | 0            | 1             | Black  | 1         |
| Diamond    | 2            | 2             | Red    | 1         |
| Club       | 3            | 3             | Black  | -1        |
| Heart      | 1            | 4             | Red    | -1        |

现在,我们将内部编程详细信息(枚举名称,枚举值)与显示设置分开,以供用户使用:

SELECT Cards.Suit 
FROM Cards
   INNER JOIN Suits ON Cards.Suit = Suits.Suit
ORDER BY Suits.Rank, 
   Card.Rank*Suits.CardOrder
2020-09-08