代码之家  ›  专栏  ›  技术社区  ›  Rob Hruska MegalomanINA

适用于枚举的持久数据

  •  23
  • Rob Hruska MegalomanINA  · 技术社区  · 16 年前

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

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

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

    • 将可能的状态持久化在状态表中,并缓存所有可能的状态域对象,以便在整个应用程序中使用
    • 只使用枚举,不持久化可用状态列表,在我和我的DBA之间制造了一场数据一致性的圣战
    • 在代码中保持状态并维护枚举,但不要将它们绑定在一起,从而创建重复的数据

    我倾向于第二种选择,尽管我的DBA声称我们的最终用户可能希望访问原始数据以生成报告,而不持久化状态会导致数据模型不完整(反驳:这可以通过文档来解决)。

    这里有大多数人使用的惯例吗?人们对每种方式的体验是什么,还有其他选择吗?

    编辑:

    经过一段时间的思考,我真正的持久性难题在于处理与数据库中的状态相关的id值。安装应用程序时,这些值将作为默认数据插入。此时,它们的id可以用作其他表中的外键。我觉得我的代码需要知道这些id,这样我就可以轻松地检索状态对象并将其分配给其他对象。我该怎么办?我可以添加另一个字段,比如“代码”,来查找内容,或者只是按名称查找状态,这很讨厌。

    8 回复  |  直到 9 年前
        1
  •  8
  •   Jason Cohen    16 年前

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

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

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

        2
  •  3
  •   Jeff Fritz    16 年前

    我使用的是你记录的三种方法的混合。..

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

    这样,如果枚举在数据库中更改了值,您的代码将被正确地无效,您将从持续集成服务器收到相应的编译错误。您对数据库中的枚举值进行了强类型绑定,不必担心在代码和数据之间手动同步值。

        3
  •  2
  •   Aaron Digulla    16 年前

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

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

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

    枚举有一个内在id(在switch()语句中使用),但当您更改元素的顺序时(例如,通过对它们进行排序或在中间添加元素),该id会发生变化。

    因此,最好的解决方案是添加toDB()和fromDB()方法以及一个附加字段。我建议为这个新字段使用简短、可读的字符串,这样您就可以解码数据库转储,而无需查找枚举。

        4
  •  1
  •   Adam Robinson    16 年前

    虽然我不熟悉Java中的“属性”概念(也不知道你使用的是哪种语言),但我通常使用代码表(或特定于域的表)的概念,并将枚举值归因于更具体的数据,例如人类可读的字符串(例如,如果我的枚举值是NewStudent,我会将其归因于“NewStudent”作为显示值)。然后,我使用Reflection检查数据库中的数据,并插入或更新记录,以便使用实际枚举值作为键ID使其与我的代码一致。

        5
  •  1
  •   lothar    16 年前

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

        6
  •  1
  •   Dmitry Ornatsky    16 年前

    如果值列表需要更新的可能性很小,那么它就是1。否则,它是3。

        7
  •  1
  •   user87581 user87581    16 年前

    好吧,我们没有DBA可以回答,所以我们更喜欢选项2)。

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

    然而,我们有一个政策,即其他人不能直接访问数据库;他们必须通过我们的网络服务来访问任何数据。这就是为什么它对我们很有效。

        8
  •  1
  •   user16120    16 年前

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

    在代码中,使用常量创建一个静态类,其名称(驼峰大小写与否)映射到描述,值映射到pk。如果您需要更多,请创建一个具有必要结构和比较运算符的类,并将其实例用作常量的值。

    如果你做得太多,可以构建一个脚本来生成实例化/声明代码。

    推荐文章