保留适合枚举的数据

时间:2009-01-29 15:37:49

标签: java types enums persistence

大多数项目都有某种类型的数据,这些数据在发行版之间基本上是静态的,非常适合用作枚举,比如状态,事务类型,错误代码等。例如,我只使用一个公共状态枚举:

public enum Status {
    ACTIVE(10, "Active");
    EXPIRED(11, "Expired");
    /* other statuses... */

    /* constructors, getters, etc. */
}

我想知道其他人在这些数据的持久性方面做了些什么。我看到了一些选项,每个选项都有一些明显的优点和缺点:

  • 在状态表中保留可能的状态,并保留所有可能的状态域对象,以便在整个应用程序中使用
  • 仅使用枚举,不要保留可用状态列表,在我和我的DBA之间创建数据一致性圣战
  • 保留状态并在代码中维护枚举,但不要将它们绑在一起,创建重复的数据

我的偏好是第二种选择,虽然我的DBA声称我们的最终用户可能想要访问原始数据来生成报告,而不是持久化状态会导致数据模型不完整(反驳:这可以解决有文件)。

大多数人在这里使用会议吗?人们对每个人的经历是什么,还有其他选择吗?

修改

在考虑了一段时间之后,我真正的持久性斗争来自于处理与数据库中的状态相关联的id值。安装应用程序时,这些值将作为默认数据插入。此时,它们具有可用作其他表中的外键的ID。我觉得我的代码需要知道这些ID,以便我可以轻松检索状态对象并将它们分配给其他对象。我该怎么办?我可以添加另一个字段,比如“代码”,查看内容,或者只是按名称查找状态,这是icky。

8 个答案:

答案 0 :(得分:8)

我们使用数据库中的一些显式字符串或字符值存储枚举值。然后从数据库值返回到枚举,我们在枚举类上编写一个静态方法来迭代并找到正确的方法。

如果你期望有很多枚举值,你可以创建一个静态映射HashMap<String,MyEnum>来快速翻译。

不要存储实际的枚举名称(即示例中的“ACTIVE”),因为开发人员很容易重构这一点。

答案 1 :(得分:3)

我正在使用您记录的三种方法的混合......

使用数据库作为Enum值的权威来源。将值存储在某种“代码”表中。每次构建时,都会为要包含在项目中的Enum生成一个类文件。

这样,如果枚举更改了数据库中的值,您的代码将被正确地无效,并且您将从Continuous Integration服务器收到适当的编译错误。您对数据库中的枚举值具有强类型绑定,并且您不必担心手动同步代码和数据之间的值。

答案 2 :(得分:2)

约书亚布洛赫在他的书“Effective Java, Second Edition”(第147页)中对枚举以及如何使用它们给出了很好的解释

在那里你可以找到各种技巧来定义你的枚举,坚持它们以及如何在数据库和你的代码之间快速映射它们(第154页)。

在Jazoon 2007的演讲中,Bloch给出了以下理由:使用额外的属性将枚举映射到数据库字段并返回:枚举是一个常量,但代码不是。为了确保编辑源的开发人员不会通过重新排序枚举或重命名而意外破坏数据库映射,您应该向枚举添加特定属性(如“dbName”)并使用它来映射它。

枚举有一个固有的id(在switch()语句中使用)但是当你改变元素的顺序时(例如通过对它们进行排序或在中间添加元素),这个id会改变。

所以最好的解决方案是添加一个toDB()和fromDB()方法以及一个额外的字段。我建议在这个新字段中使用简短易读的字符串,这样就可以解码数据库转储而无需查询枚举。

答案 3 :(得分:1)

虽然我不熟悉Java中“属性”的概念(我不知道你使用的语言是什么),但我一般都使用了代码表(或域特定表)的概念,我已经将我的枚举值归结为更具体的数据,例如人类可读的字符串(例如,如果我的枚举值是NewStudent,我会将其归结为“New Student”作为显示值)。然后我使用Reflection检查数据库中的数据并插入或更新记录,以使它们与我的代码一致,使用实际的枚举值作为密钥ID。

答案 4 :(得分:1)

我在几个世界中使用的是定义代码中的枚举和持久层(DB,文件等)中的存储表示,然后使用转换方法将它们相互映射。只有在读取或写入持久性存储时才需要使用这些转换方法,并且应用程序可以在任何地方使用类型安全枚举。在转换方法中,我使用switch语句来进行映射。如果要转换新的或未知的状态,这也允许抛出异常(通常因为应用程序或数据比另一个更新并且已声明新的或其他状态)。

答案 5 :(得分:1)

如果至少有一个很小的机会,那么值列表需要更新而不是1.否则,它是3。

答案 6 :(得分:1)

我们没有DBA可以回答,所以我们倾向于选项2)。

我们只是将Enum值保存到数据库中,当我们将数据从数据库加载到Domain Objects中时,我们只是将整数值转换为枚举类型。 这避免了选项1)和3)的任何同步问题。列表定义一次 - 在代码中。

但是,我们有一个政策,没有其他人直接访问数据库;他们必须通过我们的Web服务来访问任何数据。所以这就是为什么它适合我们。

答案 7 :(得分:1)

在您的数据库中,此“域”表的主键不必是数字。只需使用varchar pk和description列(出于dba所关注的目的)。如果您需要保证值的排序而不依赖于字母序列,只需添加一个名为“order or”sequence“的数字列。

在你的代码中,创建一个静态类,其常量的名称(camel-cased或不是)映射到描述,值映射到pk。如果您需要更多,请创建一个具有必要结构和比较运算符的类,并使用它的实例作为常量的值。

如果执行此操作太多,请构建一个脚本以生成实例/声明代码。