Заполните перечисление значениями из базы данных - PullRequest
22 голосов
/ 12 мая 2009

У меня есть таблица, которая отображает String-> Integer.

Вместо того чтобы создавать перечисление статически, я хочу заполнить перечисление значениями из базы данных. Это возможно?

Итак, вместо того, чтобы делить это статически:

public enum Size { SMALL(0), MEDIUM(1), LARGE(2), SUPERSIZE(3) };

Я хочу создать это перечисление динамически, поскольку числа {0,1,2,3} в основном случайные (поскольку они автоматически генерируются столбцом AUTOINCREMENT базы данных).

Ответы [ 6 ]

30 голосов
/ 12 мая 2009

Нет. Перечисления всегда фиксируются во время компиляции. Единственный способ сделать это - сгенерировать соответствующий байт-код динамически.

Сказав это, вы, вероятно, должны решить, какие аспекты перечисления вам действительно интересны. Предположительно, вы не хотели использовать оператор switch над ними, поскольку это означало бы статический код, а вы не t знать значения статически ... также любые другие ссылки в коде.

Если вам действительно нужна карта от String до Integer, вы можете просто использовать Map<String, Integer>, который вы заполняете во время выполнения, и все готово. Если вам нужны функции EnumSet, их будет несколько сложнее воспроизвести с той же эффективностью, но это может быть осуществимо с некоторыми усилиями.

Итак, прежде чем идти дальше с точки зрения размышлений о реализации, я предлагаю вам разобраться, каковы ваши реальные требования.

(РЕДАКТИРОВАТЬ: я предполагал, что это перечисление является полностью динамическим, т. Е. Что вы не знаете имен или даже сколько их значений. Если набор имен фиксирован, и вы только нужно получить идентификатор из базы данных, это совсем другое дело - см. ответ Андреаса .)

25 голосов
/ 12 мая 2009

Это немного сложно, поскольку заполнение этих значений происходит во время загрузки класса. Поэтому вам потребуется статический доступ к соединению с базой данных.

Как бы я ни ценил его ответы, я думаю, что на этот раз Джон Скит может ошибаться.

Взгляните на это:

public enum DbEnum {
    FIRST(getFromDb("FIRST")), SECOND(getFromDb("second"));

    private static int getFromDb(String s) {
        PreparedStatement statement = null;
        ResultSet rs = null;
        try {
            Connection c = ConnectionFactory.getInstance().getConnection();
            statement = c.prepareStatement("select id from Test where name=?");
            statement.setString(1, s);
            rs = statement.executeQuery();
            return rs.getInt(1);

        }
        catch (SQLException e) {
           throw new RuntimeException("error loading enum value for "+s,e);
        }
        finally {
            try {
                rs.close();
                statement.close();
            } catch (SQLException e) {
                //ignore
            }
        }
        throw new IllegalStateException("have no database");
    }

    final int value;

    DbEnum(int value) {
        this.value = value;
    }
}
6 голосов
/ 20 ноября 2012

Улучшение того, что сделал Андреас , вы можете загрузить содержимое базы данных в карту, чтобы уменьшить количество необходимых соединений с базой данных.

public enum DbEnum {
    FIRST(getFromDb("FIRST")),
    SECOND(getFromDb("second"));

    private Map<String,Integer> map;
    private static int getFromDB(String s)
    {
        if (map == null)
        {
           map = new HashMap<String,Integer>();
           // Continue with database code but get everything and
           // then populate the map with key-value pairs.
           return map.get(s);
        }
        else {
            return map.get(s); }
    }
}
3 голосов
/ 12 мая 2009

Перечисления не являются динамическими, поэтому краткий ответ заключается в том, что вы не можете это сделать.

Также взгляните на вопрос переполнения стека Динамическое перечисление в C # .

1 голос
/ 12 мая 2009

Вам необходимо скопировать в коде то, что находится в базе данных (или наоборот). Посмотрите этот вопрос для некоторых хороших советов.

0 голосов
/ 12 мая 2009

На всех языках, которые я знаю, перечисления являются статическими. Компилятор может сделать некоторые оптимизации на них. Поэтому короткий ответ - нет, вы не можете.

Вопрос в том, почему вы хотите использовать перечисление таким образом. Что вы ожидаете? Или, другими словами, почему бы не использовать коллекцию вместо этого?

...