在Java应用程序中处理引用数据的类型安全方法



在这个时间点上,除了"我们一直都是这样做的"之外,可能没有其他好的理由,新系统是如何构建的,以使用用于表示状态代码的参考数据?

例如,一个案例可能有两个有效状态,"打开"或"关闭"。从历史上看,我见过许多系统,其中这些有效值将存储在包含此参考数据的数据库表中,并被称为代码类型("CaseStatus"),每个有效值都有一个"代码"值(例如"OPN")和一个解码或显示值,当需要向用户显示该值时(在这种情况下为"打开")使用该值。

如果今天开发一个基于Java的系统,从类型安全的代码角度来看,我们会定义这样的Enum:

public enum CaseStatus{
    Open("OPN"),
    Closed("CLS");
    private String codeValue;
    private CaseStatus(String codeValue){
        this.codeValue = codeValue;
    }
}

仅从源代码的角度来看,这很好,Enum通过有效值的受限列表来强制执行类型安全,但就其本身而言,数据库中没有此代码类型或其有效值的表示。如果有直接针对数据库运行即席报告的数据用户,他们需要一种方法来查找"OPN"、"CLS"的解码值。从历史上看,这将使用包含代码类型、代码及其解码值的参考表来完成。

我们继续使用这些状态代码值作为"3个字母的代码",这似乎很奇怪,此时的动机不再是因为我们需要节省数据库中的空间(无论如何,"OPN"与"Open"都不是一个很好的优化)。

人们在最近研究的系统中还使用或看到了哪些其他方法?您是只在数据库中、只在代码中还是在两个地方维护引用数据?如果在两个位置都维护引用数据,您会使用什么方法来保持两者同步?

首先,如果只有两个可能的值,并且不可能期望它们发展成更大的数字(如open/closed的示例),我可能会将status_open列定义为BOOLEANSMALLINT(0/1)或CHAR(Y/N)。

当状态的范围更大(或者可能增加到两个以上的值)时,我会使用代理键。虽然节省几个字节几乎不是一种优化,但对CHAR值列进行索引和连接比对INTEGER列进行索引或连接更昂贵。虽然我没有关于INTEGERCHAR(3)问题的度量标准,但我认为在这种情况下,差异不会像INTEGER与CHAR(50)的情况那样大。

然而,我在小型CHAR缩写中发现的一个缺点是,有时很难找到有意义的值。假设您的状态为"已损坏-已订购更换",如果我将其称为"BRO"会有帮助吗?它比称之为3更好吗?

另一方面,即使模型不需要它,我也发现在status上添加一个短的VARCHAR列很方便,可以描述每个助记符或代理键的含义。(模型长大后,很难记住所有这些!)

我的实现(在特定情况下有适当的例外)可能是:

在Java方面,就是你定义的枚举。

在SQL方面:

CREATE TABLE status (
  id INTEGER PRIMARY KEY,
  description VARCHAR(40)
)
CREATE TABLE entity (
 ...
 status_id INTEGER REFERENCES status(id)
)
INSERT INTO status VALUES (0,'Closed');
INSERT INTO status VALUES (1,'Open');
INSERT INTO status VALUES (2,'Broken - replacement has been ordered');

我遇到的一个解决方案是在数据库中使用物化视图来动态重新计算非规范化关系。在基于文档的数据库中,您可能会将CaseStatus存储为String。最后,您可以使用ORM工具将CaseStatus存储为Object,但在我熟悉的情况下,参考数据存储在数据库中(如果您将其存储在代码中,则需要构建和部署到生产环境中,并对版本进行额外测试)。

最新更新