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

发布于 2024-07-17 04:46:23 字数 111 浏览 7 评论 0原文

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

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

How would I implement a enumeration field in a database that doesn't support enumerations? (i.e. SQLite)

The fields need to be easily searchable with "field = ?" so using any type of data serialization is a bad idea.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

情未る 2024-07-24 04:46:23

我使用的方法是使用查找表的外键。 事实上,即使我使用支持 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 您可以必须使用ALTER TABLE来重新定义列表。

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

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

除了查找表之外的另一个选择是使用 CHECK 约束(前提是数据库支持它们——MySQL 在版本 8.0.16 之前不支持 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 相同的缺点:在没有 ALTER TABLE 的情况下很难更改值列表,很难查询列表允许的值,很难注释值。

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

Using a foreign key to a lookup table is the approach I use. In fact, I use this even when I do use a database that supports ENUM (e.g. MySQL).

For simplicity, I may skip the ever-present "id" for the lookup table, and just use the actual value I need in my main table as the primary key of the lookup table. That way you don't need to do a join to get the value.

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)
);

Admittedly, storing strings takes more space than MySQL's implementation of ENUM, but unless the table in question has millions of rows, it hardly matters.

Other advantages of the lookup table are that you can add or remove a value from the list with a simple INSERT or DELETE, whereas with ENUM you have to use ALTER TABLE to redefine the list.

Also try querying the current list of permitted values in an ENUM, for instance to populate a pick-list in your user interface. It's a major annoyance! With a lookup table, it's easy: SELECT status from BugStatus.

Also you can add other attribute columns to the lookup table if you need to (e.g. to mark choices available only to administrators). In an ENUM, you can't annotate the entries; they're just simple values.

Another option besides a lookup table would be to use CHECK constraints (provided the database supports them -- MySQL doesn't support CHECK until version 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'))
);

But this use of a CHECK constraint suffers from the same disadvantages as the ENUM: hard to change the list of values without ALTER TABLE, hard to query the list of permitted values, hard to annotate values.

PS: the equality comparison operator in SQL is a single =. The double == has no meaning in SQL.

寄风 2024-07-24 04:46:23

为了限制可能的值,我将使用保存枚举项的表的外键。

如果您不想 JOIN 进行搜索,则将键设置为 varchar(如果 JOINS 不是问题),则将键设置为 INT,并且除非您需要在该字段上搜索,否则不要加入。

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

To restrict the possible values I would use a foreign key to a table that holds the enumeration items.

If you don't want to JOIN to do your searches then make the key a varchar if JOINS are not a problem then make the key an INT and don't join unless you need to search on that field.

Note that putting your enumerations in the DB precludes compile time checking of the values in your code (unless you duplicate the enumeration in code.) I have found this to be a large down side.

又爬满兰若 2024-07-24 04:46:23

你基本上有两个选择:

  • 使用整数字段

  • 使用varchar字段

我个人提倡使用varchar,因为你不会如果你改变枚举+字段是人类可读的,那么会破坏任何东西,但是整数也有一些优点,即性能(数据的大小是一个明显的例子)

You basically have two options :

  • use an integer field

  • use a varchar field

I would personally advocate the use of varchars, because you won't break anything if you change your enum + the fields are human-readable, but ints have some pro aswell, namely performance (the size of the data is an obvious example)

剩一世无双 2024-07-24 04:46:23

这就是我最近所做的

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

此设置器需要一个枚举
还有另一个接受 String 的 setter,但这是私有的(或者您可以直接映射该字段,如果您愿意的话)。

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

如果我错过了你的问题,我深表歉意。

This is what I did recently

In my hibernate mapped POJO- I kept the type of the member as String and it is VARCHAR in the database.

The setter for this takes an enum
There is another setter which takes String- but this is private (or you can map the field directly- if that's what you prefer.)

Now the fact I am using String is encapsulated from all. For the rest of the application- my domain objects use enum.
And as far as the database is concerned- I am using String.

If I missed your question- I apologize.

不回头走下去 2024-07-24 04:46:23

如果您将 Spring JPA 2.1 或更高版本与 hibernate 一起使用,您可以实现自己的 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);
    }
}

请参阅文章中的第四个解决方案 在 JPA 中持久化枚举。代码片段也来自那里。

If you use Spring JPA 2.1 or later with hibernate you can implement your own AttributeConverter and define how your enum maps to column values

@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);
    }
}

Please see the 4th solution in the article at Persisting Enums in JPA.The code snippet is also from there.

美胚控场 2024-07-24 04:46:23

我会使用 varchar。 这不适合您吗?

I would use a varchar. Is this not an option for you?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文