Peupler un enum avec des valeurs de la base de données

j'ai une table qui maps String->Integer.

plutôt que de créer un enum statically, je veux peupler l'enum avec des valeurs d'une base de données. Est-ce possible ?

ainsi, plutôt que de delcaring ce statically:

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

je veux créer cet enum dynamiquement puisque les nombres {0,1,2,3} sont fondamentalement aléatoires (parce qu'ils sont autogénérés par la colonne auto-ordonnancement de la base de données).

21
demandé sur Jacques René Mesrine 2009-05-12 10:46:11

6 réponses

Pas de. Les énums sont toujours fixés lors de la compilation. La seule façon de le faire serait de générer dyamiquement le bytecode correspondant.

cela dit, vous devriez probablement trouver quels aspects d'un enum vous intéressent. Vous ne vouliez probablement pas utiliser une instruction switch au-dessus d'eux, car cela signifierait un code statique et vous ne connaissez pas les valeurs statiquement... de même, toute autre référence dans le code.

si vous voulez vraiment juste une carte de String à Integer , vous pouvez juste utiliser un Map<String, Integer> que vous peuplez au moment de l'exécution, et vous êtes fait. Si vous voulez les caractéristiques EnumSet , ils seraient un peu plus difficile à reproduire avec la même efficacité, mais il peut être faisable avec un certain effort.

donc, avant d'aller plus loin en termes de réflexion sur la mise en œuvre, je vous suggère de travailler sur ce que vos besoins réels sont.

(EDIT: i've j'ai supposé que cet enum est entièrement dynamique, c.-à-d. que vous ne connaissez pas les noms ou même combien de VALEURs il y a. Si le jeu de noms est fixe et vous seulement besoin de récupérer L'ID de la base de données, c'est une question très différente - voir Andreas' réponse .)

29
répondu Jon Skeet 2017-05-23 10:30:59

c'est un peu délicat, puisque la population de ces valeurs se produit au moment de la charge de la classe. Vous aurez donc besoin d'un accès statique à une connexion de base de données.

bien que j'apprécie ses réponses, je pense que Jon Skeet peut se tromper cette fois.

regardez ça:

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;
    }
}
23
répondu Andreas Petersson 2014-03-25 15:53:47

améliorer sur ce Qu'Andreas a fait , vous pouvez charger le contenu de la base de données dans une carte pour réduire le nombre de connexions de base de données nécessaires.

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
répondu Tigertron 2017-05-23 12:34:51

les Énums ne sont pas dynamiques, donc la réponse courte est que vous ne pouvez pas le faire.

regardez aussi la question sur le débordement de la pile enum dynamique dans C# .

3
répondu aleemb 2017-05-23 12:34:50

vous devez répliquer en code ce qui est dans la base de données (ou vice-versa). Voir ce question pour quelques bons conseils.

1
répondu kgiannakakis 2017-05-23 12:34:50

dans toutes les langues que je connais, les énums sont statiques. Le compilateur peut les optimiser. Par conséquent, la réponse courte est non, vous ne pouvez pas.

la question est pourquoi vous voulez utiliser un enum de cette façon. Qu'attendez-vous? Ou en d'autres termes, pourquoi ne pas utiliser une collection à la place?

0
répondu Luixv 2009-05-12 06:57:14