如何在数据库中处理没有枚举字段的枚举?

时间:2009-04-17 16:46:39

标签: database-design enums

如何在不支持枚举的数据库中实现枚举字段? (即SQLite)

需要使用“field =?”轻松搜索字段所以使用任何类型的数据序列化是一个坏主意。

6 个答案:

答案 0 :(得分:53)

使用外键到查找表是我使用的方法。实际上,即使我使用支持ENUM的数据库(例如MySQL),我也会使用它。

为简单起见,我可以跳过查找表中始终存在的“id”,只使用我主表中需要的实际值作为查找表的主键。这样您就不需要进行连接来获取值。

CREATE TABLE BugStatus (
  status            VARCHAR(20) PRIMARY KEY
);

INSERT INTO BugStatus (status) VALUES ('NEW'), ('OPEN'), ('FIXED');

CREATE TABLE Bugs (
  bug_id            SERIAL PRIMARY KEY,
  summary           VARCHAR(80),
  ...
  status            VARCHAR(20) NOT NULL DEFAULT 'NEW',
  FOREIGN KEY (status) REFERENCES BugStatus(status)
);

不可否认,存储字符串比MySQL ENUM的实现占用更多空间,但除非有问题的表有数百万行,否则几乎不重要。

查找表的其他优点是您可以使用简单的INSERTDELETE在列表中添加或删除值,而使用ENUM则必须使用{{1重新定义列表。

还尝试查询ALTER TABLE中允许值的当前列表,例如填充用户界面中的选择列表。这是一个很大的烦恼!使用查找表,很简单:ENUM

如果需要,您还可以将其他属性列添加到查找表中(例如,标记仅供管理员使用的选项)。在SELECT status from BugStatus中,您无法注释条目;他们只是简单的价值观。

查找表之外的另一个选择是使用 ENUM约束(假设数据库支持它们 - MySQL不支持):

CHECK

但是这种CREATE TABLE Bugs ( bug_id SERIAL PRIMARY KEY, summary VARCHAR(80), ... status VARCHAR(20) NOT NULL CHECK (status IN ('NEW', 'OPEN', 'FIXED')) ); 约束的使用与CHECK具有相同的缺点:很难更改没有ENUM的值列表,很难查询允许值列表,难以注释价值观。

PS:SQL中的等式比较运算符是单个ALTER TABLE。双=在SQL中没有任何意义。

答案 1 :(得分:2)

要限制可能的值,我会将外键用于包含枚举项的表。

如果您不想JOIN进行搜索,那么如果JOINS不是问题,则将密钥设为varchar,然后将密钥设为INT并且不加入,除非您需要搜索该字段。

请注意,将您的枚举放入数据库会妨碍编译时检查代码中的值(除非您在代码中复制枚举。)我发现这是一个很大的缺点。

答案 2 :(得分:1)

您基本上有两个选择:

  • 使用整数字段

  • 使用varchar字段

我个人主张使用varchars,因为如果改变你的enum +你不会破坏任何东西+字段是人类可读的,但是int有一些pro,也就是性能(数据的大小是显而易见的)例如)

答案 3 :(得分:0)

这是我最近所做的

在我的hibernate映射的POJO中 - 我将成员的类型保留为String,并且它在数据库中是VARCHAR。

这个的setter需要一个枚举 还有另一个带有字符串的setter,但这是私有的(或者你可以直接映射字段 - 如果这是你喜欢的。)

现在我使用String的事实是从所有人封装的。对于应用程序的其余部分 - 我的域对象使用枚举。 就数据库而言 - 我正在使用String。

如果我错过了你的问题 - 我道歉。

答案 4 :(得分:0)

如果您在 Hibernate 中使用 Spring JPA 2.1 或更高版本,您可以实现自己的 AttributeConverter 并定义您的枚举如何映射到列值

@Converter(autoApply = true)
public class CategoryConverter implements AttributeConverter<Category, String> {
 
    @Override
    public String convertToDatabaseColumn(Category category) {
        if (category == null) {
            return null;
        }
        return category.getCode();
    }

    @Override
    public Category convertToEntityAttribute(String code) {
        if (code == null) {
            return null;
        }

        return Stream.of(Category.values())
          .filter(c -> c.getCode().equals(code))
          .findFirst()
          .orElseThrow(IllegalArgumentException::new);
    }
}

请参阅 Persisting Enums in JPA 文章中的第 4 个解决方案。代码片段也来自那里。

答案 5 :(得分:-1)

我会使用varchar。这不是你的选择吗?