Database design 如何处理数据库中没有枚举字段的枚举?
如何在不支持枚举的数据库中实现枚举字段?i、 e.SQLiteDatabase design 如何处理数据库中没有枚举字段的枚举?,database-design,enums,Database Design,Enums,如何在不支持枚举的数据库中实现枚举字段?i、 e.SQLite 需要使用field=?轻松搜索字段?因此,使用任何类型的数据序列化都是一个坏主意。我会使用varchar。这不是你的选择吗?你基本上有两个选择: 使用整数字段 使用varchar字段 我个人主张使用varchars,因为如果更改enum+字段,您不会破坏任何东西,但int也有一些优点,即性能数据的大小是一个明显的例子,为了限制可能的值,我将使用外键来保存枚举项的表 如果不想加入进行搜索,则将键设为varchar如果加入不是问题,则将
需要使用field=?轻松搜索字段?因此,使用任何类型的数据序列化都是一个坏主意。我会使用varchar。这不是你的选择吗?你基本上有两个选择: 使用整数字段 使用varchar字段
我个人主张使用varchars,因为如果更改enum+字段,您不会破坏任何东西,但int也有一些优点,即性能数据的大小是一个明显的例子,为了限制可能的值,我将使用外键来保存枚举项的表 如果不想加入进行搜索,则将键设为varchar如果加入不是问题,则将键设为INT,除非需要在该字段上搜索,否则不要加入 请注意,将枚举放在DB中会阻止编译时检查代码中的值,除非在代码中复制枚举。我发现这是一个很大的缺点。我使用的方法是在查找表中使用外键。事实上,即使我使用了一个支持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实现占用更多的空间,但除非所讨论的表有数百万行,否则这几乎不重要
查找表的其他优点是,您可以通过简单的插入或删除操作从列表中添加或删除值,而使用ENUM时,您必须使用ALTER table来重新定义列表
还可以尝试查询枚举中允许值的当前列表,例如,在用户界面中填充拾取列表。这真是个大麻烦!使用查找表,很容易:从BugStatus中选择status
此外,如果需要,您还可以向查找表中添加其他属性列,例如标记仅对管理员可用的选项。在枚举中,不能对条目进行注释;它们只是简单的值
除了查找表之外的另一个选项是使用检查约束,前提是数据库支持它们-MySQL在8.0.16版本之前不支持检查:
CREATE TABLE Bugs (
bug_id SERIAL PRIMARY KEY,
summary VARCHAR(80),
...
status VARCHAR(20) NOT NULL
CHECK (status IN ('NEW', 'OPEN', 'FIXED'))
);
但是,这种使用检查约束的方法与枚举具有相同的缺点:在不更改表的情况下很难更改值列表,很难查询允许值列表,很难注释值
PS:SQL中的相等比较运算符是单=。double==在SQL中没有任何意义。这就是我最近所做的 在hibernate映射的POJO中,我将成员的类型保留为字符串,并且在数据库中是VARCHAR 此设置程序采用枚举 还有另一个setter,它接受字符串-但这是私有的,或者您可以直接映射字段-如果您喜欢的话 现在,我正在使用字符串的事实从所有方面进行了封装。对于应用程序的其余部分,我的域对象使用enum。 就数据库而言,我使用的是字符串
如果我没有回答您的问题,我很抱歉。如果您在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);
}
}
请参阅文章中的第4个解决方案。代码片段也在那里。如果这是重复的,请小心。在我提问之前,我确实在StackOverflow上寻找答案。使用VARCHAR会导致数据非规范化。如果要更改枚举值的名称,则需要对整个表进行更新,而不仅仅是更改引用表中的一行。这很有意义。Ruby on Rails将允许与验证相同的行为作为奖励。感谢=vs.==这件事:我已经有一段时间没有直接使用SQL了。这是一个有点老的问题,但答案很棒。投票赞成。值得注意的是,只有当您愿意/有兴趣使用INNODB而不是MyISAM时,才可以在MySQL中使用它。@mOrloff:对,INNODB支持外键约束,但MyISAM不支持外键约束。使用InnoDB而不是MyISAM绝对是最佳实践,原因有很多,这只是其中之一。最好的答案,10年后,+1来自我