如何在不支持枚举的数据库中实现枚举字段? (即SQLite)
需要使用“field
=?”轻松搜索字段所以使用任何类型的数据序列化是一个坏主意。
答案 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
的实现占用更多空间,但除非有问题的表有数百万行,否则几乎不重要。
查找表的其他优点是您可以使用简单的INSERT
或DELETE
在列表中添加或删除值,而使用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。这不是你的选择吗?