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

新手上路,请多包涵

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

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

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

更新

感谢所有真棒和快速的答案!正如我所怀疑的那样。

但是,对 toolkit 的说明:这是一种方法。问题是我必须向我创建的每个枚举类型添加相同的方法。这是很多重复的代码,目前,Java 不支持任何解决方案(Java 枚举不能扩展其他类)。

原文由 user20298 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.4k
2 个回答

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

 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"]);

问题在于过去盯着 Enterprise Manager 并试图破译:

 Name          Suit
------------  ----
Kylie Guénin  2
Ian Boyd      1

诗句

Name          Suit
------------  -------
Kylie Guénin  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 }

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

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

问题出现了:假设我想订购这些值。有些人可能希望按 enum 的序数值对它们进行排序。当然,按枚举的数值排序卡片是没有意义的:

 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 维度表

套装西装编号秩颜色未知4 0无效的心1 1红色的俱乐部3 2黑色的钻石2 3红色的铲0 4黑色的

这样,当您想更改您的卡片以使用 Kissing Kings New Deck Order 时,您可以将其更改为显示目的,而不会丢弃所有数据:

套装西装编号秩颜色卡令未知4 0无效的无效的铲0 1黑色的1钻石2 2红色的1俱乐部3 3黑色的-1心1 4红色的-1

现在,我们将内部编程细节(枚举名称、枚举值)与用于用户的显示设置分开:

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


原文由 Ian Boyd 发布,翻译遵循 CC BY-SA 4.0 许可协议

除非您有特定的性能原因来避免它,否则我建议使用单独的表进行枚举。使用外键完整性,除非额外的查找真的要了你的命。

套装表:

 suit_id suit_name
1       Clubs
2       Hearts
3       Spades
4       Diamonds

玩家表

player_name suit_id
Ian Boyd           4
Shelby Lake        2

  1. 如果您曾经将枚举重构为具有行为(例如优先级)的类,那么您的数据库已经正确地对其进行了建模
  2. 您的 DBA 很高兴,因为您的模式已规范化(每个玩家存储一个整数,而不是整个字符串,可能有也可能没有拼写错误)。
  3. 您的数据库值 ( suit_id ) 独立于您的枚举值,这也有助于您处理来自其他语言的数据。

原文由 Tom 发布,翻译遵循 CC BY-SA 2.5 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题