使用和保存枚举的最佳做法

sle*_*ske 75 c# java database enums persistence

我在这里看到了几个关于处理和保持类似枚举值的最佳方法的问题/讨论(例如,坚持适用于枚举的数据,如何使用NHibernate保持枚举),我想问一般的共识是什么.

特别是:

  • 如何在代码中处理这些值?
  • 它们应该如何持久保存到数据库中(如文本/数字)?
  • 不同解决方案的权衡是什么?

注意:我将原本包含在此问题中的解释移到了答案中.

Pau*_*ier 18

我同意你所说的很多内容.但是,有一件事我想补充一下enums的持久性:我不相信在构建时从DB值生成枚举是可以接受的,但我也认为运行时检查不是一个好的解决方案.我将定义第三种方法:进行单元测试,检查枚举对数据库的值.这可以防止"随意"分歧,并避免每次运行代码时对数据库检查枚举的开销.


小智 13

最初的文章对我来说很好.尽管如此,基于这些评论,似乎有些关于Java枚举的评论可能会澄清一些事情.

根据定义,Java中的枚举类型是一个类,但许多程序员倾向于忘记这一点,因为他们宁愿将其与"允许值列表"相关联,就像在其他一些语言中一样.它不止于此.

因此,为了避免这些switch语句,在枚举类中放置一些代码和其他方法可能是合理的.几乎从来没有必要创建一个单独的"枚举类真实类".

还要考虑文档的要点 - 您是否要记录数据库中枚举的实际含义?在反映值(您的枚举类型)或某些外部文档的源代码中?我个人更喜欢源代码.

如果由于速度或任何原因要将枚举值作为整数呈现在数据库中,那么该映射也应该驻留在Java枚举中.默认情况下,您将获得字符串名称映射,我一直对此感到满意.有一个与每个枚举值相关联的序数,但直接使用它作为代码和数据库之间的映射并不是很明亮,因为如果有人重新排序源代码中的值,那么序号将会改变.或者在现有值之间添加额外的枚举值.或删除一些价值.

(当然,如果有人在源代码中更改了枚举的名称,那么默认的字符串映射也会变坏,但不太可能意外发生.如果有必要,可以通过进行一些运行时检查来更轻松地防止这种情况发生.并按照此处的建议检查数据库中的约束.)


sle*_*ske 7

我试图总结一下我的理解.如果您有任何更正,请随时编辑此内容.所以这里:

在代码中

在代码中,应使用语言的本机枚举类型(至少在Java和C#中)或使用类似"类型安全枚举模式"的方式来处理枚举.不鼓励使用普通常量(整数或类似),因为您失去了类型安全性(并且很难理解哪些值是例如方法的合法输入).

这两者之间的选择取决于枚举附加了多少附加功能:

  • 如果你想将大量的功能放入枚举(这很好,因为你总是避免切换()),一个类通常更合适.
  • 另一方面,对于简单的类似枚举的值,语言的枚举通常更清晰.

特别是,至少在Java中,枚举不能从另一个类继承,所以如果你有几个具有类似行为的枚举,你想把它们放到一个超类中,你就不能使用Java的枚举.

坚持使用枚举

要保留枚举,应为每个枚举值分配唯一的ID.这可以是整数,也可以是短字符串.首选短字符串,因为它可以是助记符(使DBA等更容易理解数据库中的原始数据).

  • 在软件中,每个枚举应该具有映射函数,以在枚举(在软件内部使用)和ID值(用于持久化)之间进行转换.一些框架(例如(N)Hibernate)为自动执行此操作提供了有限的支持.否则,您必须将它放入枚举类型/类中.
  • 数据库应该(理想情况下)包含列出合法值的每个枚举的表.一列是ID(见上文),即PK.附加列可能对例如描述有意义.然后,包含该枚举值的所有表列都可以使用此"枚举表"作为FK.这可以保证永远不会保留不正确的枚举值,并允许DB"独立".

这种方法的一个问题是合法枚举值列表存在于两个地方(代码和数据库).这很难避免,因此通常被认为是可以接受的,但有两种选择:

  • 只保留数据库中的值列表,在构建时生成枚举类型.优雅,但意味着构建运行需要数据库连接,这似乎有问题.
  • 在代码中定义值列表以具有权威性.在运行时(通常在启动时)检查DB中的值,在不匹配时进行抱怨/中止.


Qui*_*ome 6

在C#的代码处理中,你错过了定义delcaring 0值的方法.我几乎总是将我的第一个值声明为:

public enum SomeEnum
{
    None = 0,
}
Run Code Online (Sandbox Code Playgroud)

以便作为空值.因为支持类型是一个整数,整数默认为0所以它在很多地方非常有用,可以知道枚举是否实际上是以编程方式设置的.

  • 我不同意.这只有在你有时保留未初始化的变量时才有意义,我认为这是非常糟糕的做法.我经常看到这个有"无"值的想法,但我相信它只隐藏了真正的问题(未初始化的变量). (5认同)
  • 它是如何隐藏问题的?它使它像一个可空的int显式.我在代码中保留了未初始化的值,因为我知道CLR默认将它们设置为什么.他们仍然初步认为它是隐含的. (3认同)

Dav*_*ike 5

Java或C#应始终在代码中使用枚举.免责声明:我的背景是C#.

如果要将值持久化到数据库,则应显式定义每个枚举成员的整数值,以便稍后的代码更改不会意外地更改已转换的枚举值,从而改变应用程序行为.

值应始终作为整数值持久保存到数据库,以防止枚举名称重构.在Wiki中保留每个枚举的文档,并在数据库字段中添加注释,指向记录该类型的Wiki页面.还要将XML文档添加到包含指向wiki条目的链接的枚举类型,以便通过Intellisense提供.

如果使用工具生成CRUD代码,它应该能够定义用于列的枚举类型,以便生成的代码对象始终使用枚举成员.

如果需要为枚举成员应用自定义逻辑,则可以使用以下选项:

  • 如果您有一个枚举MyEnum,请创建一个静态类MyEnumInfo,它提供实用程序方法,通过switch语句或任何必要的方法发现有关枚举成员的其他信息.将"Info"附加到类名中枚举名称的末尾可确保它们在IntelliSense中彼此相邻.
  • 使用属性装饰枚举成员以指定其他参数.例如,我们开发了一个EnumDropDown控件,它创建一个填充枚举值的ASP.NET下拉列表,EnumDisplayAttribute指定用于每个成员的格式良好的显示文本.

我没有尝试过这个,但是对于SQL Server 2005或更高版本,理论上可以将C#代码注册到包含枚举信息的数据库以及将值转换为枚举以在视图或其他构造中使用的能力,从而制作翻译方法数据以DBA更容易使用的方式.