web-dev-qa-db-ja.com

データベースからの値を列挙型に入力します

String-> Integerをマップするテーブルがあります。

Enumを静的に作成するのではなく、enumにデータベースからの値を入力します。これは可能ですか?

したがって、これを静的に削除するのではなく、次のようにします。

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

数値{0,1,2,3}は基本的にランダムであるため(データベースのAUTOINCREMENT列によって自動生成されるため)、この列挙型を動的に作成したいと思います。

24

いいえ。列挙型は常にコンパイル時に修正されます。これを行う唯一の方法は、関連するバイトコードを動的に生成することです。

そうは言っても、おそらく列挙型のどの部分に実際に関心があるかを考え出す必要があります。おそらく、静的コードを意味するため、それらに対してswitchステートメントを使用したくなかったでしょう値を静的に知る...コード内の他の参照と同様に。

本当にStringからIntegerへのマップが必要な場合は、実行時に入力するMap<String, Integer>を使用するだけで、完了です。 EnumSet機能が必要な場合は、同じ効率で再現するのがやや難しいかもしれませんが、多少の努力で実現できる場合があります。

そのため、実装について考える前に、実際の要件を理解することをお勧めします。

(編集:この列挙型は完全に動的であると想定しています。つまり、名前や値がいくつあるかさえわかりません。名前のセットが固定されていて、 onlyデータベースからIDをフェッチする必要がありますが、これはまったく別の問題です Andreasの回答 を参照してください。

31
Jon Skeet

これらの値の入力はクラスのロード時に行われるため、これは少し注意が必要です。したがって、データベース接続への静的アクセスが必要になります。

私は彼の答えを大切にしていますが、今回はジョン・スキートが間違っているのではないかと思います。

これをみて:

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;
    }
}
26

Andreasが行ったこと の改善により、データベースの内容をマップにロードして、必要なデータベース接続の数を減らすことができます。

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); }
    }
}
6
Tigertron

列挙型は動的ではないので、簡単に言えば、それはできないということです。

スタックオーバーフローの質問C#の動的列挙もご覧ください。

3
aleemb

データベースにあるものをコードで複製する必要があります(またはその逆)。いくつかの良いアドバイスについては、これを参照してください 質問

1
kgiannakakis

私が知っているすべての言語では、列挙型は静的です。コンパイラーはそれらに対していくつかの最適化を行うことができます。したがって、簡単な答えは「いいえ」です。

問題は、なぜこのように列挙型を使用したいのかということです。何を期待しますか?または、言い換えると、代わりにコレクションを使用しないのはなぜですか?

0
Luixv