Prev: Is there any ActiveRecord implementation for java?
Next: CFP: PPPJ 2010 -- Principles and Practice of Programming in Java (Vienna, Sep 10)
From: david.karr on 18 Dec 2009 18:42 Quite often databases will have columns that are stored as integers, but represent enumerated values. In object-relational mapping, it's a good idea to translate that integer value to the enumerated value it represents. The built-in "ordinal" value of an enum is almost useless. The integer values for an enum always need to be controlled, and can't change if you reorder things. So you at least have to implement one custom field in the enum, which I'll call "columnValue". Somewhere you have to have code that translates those integer values into the enumerated type value. The best place to do that is within the enumerated type itself. Ideally, I'd like to do this in a way that doesn't repeat the integer values, and is reasonably efficient. A simple-minded implementation might look like this: public static enum SomeType { Foo(101), Bar(100), Gork(4001); private int columnValue; public final int getColumnValue() { return columnValue; } public final void setColumnValue(int columnValue) { this.columnValue = columnValue; } public SomeType getEnum(int columnValue) { switch (columnValue) { case 101: return Foo; case 100: return Bar; case 4001: return Gork; default: return null; } } SomeType(int columnValue) { this.columnValue = columnValue; } } Can someone think of a better way to do this, that doesn't repeat the column values?
From: Peter Duniho on 18 Dec 2009 18:53 david.karr wrote: > Quite often databases will have columns that are stored as integers, > but represent enumerated values. In object-relational mapping, it's a > good idea to translate that integer value to the enumerated value it > represents. > > The built-in "ordinal" value of an enum is almost useless. The integer > values for an enum always need to be controlled, and can't change if > you reorder things. [...] I guess I don't really get this. I see two choices: the enum values never change, or they may change. You seem to be saying that a situation where they may never change is bad. That the code needs to be able to allow them to change. But you still want to store integers in the database. So now you have a completely different set of integers that can never change. How is that better than just not allowing the enum values to ever change? On the other hand, if you simply want to keep the enum implementation completely separate from the database implementation, I would think that putting the mapping into the enum type itself doesn't make much sense either. A mapping in a completely separate class would seem more appropriate. You could even use different versions of the class if the mapping needed to change at some point, selecting the version according to the version of the database you're accessing. As for the code you posted, I don't understand its purpose. You seem to be using the exact same numerical values for the integers and enum values. Why have the switch statement at all? Why not return an enum instance set to the passed-in "columnValue"? I'm also a little confused by the "setColumnValue()" method, as it implies to me that there's the expectation of a mutable enum instance. I would normally expect an enum instance to be immutable. But that's probably just an artifact of my relative unfamiliarity with Java's implementation of enums. Pete
From: EJP on 18 Dec 2009 19:25 david.karr wrote: > Can someone think of a better way to do this, that doesn't repeat the > column values? Have each enum value enter itself on construction into a Map<Integer, YourEnum> with its own ColumnValue as the key. Like Peter I cannot see the point of setColumnValue(), and the Map would of course require the columnValue to be constant.
From: markspace on 18 Dec 2009 19:54 david.karr wrote: > The built-in "ordinal" value of an enum is almost useless. The integer > values for an enum always need to be controlled, and can't change if > you reorder things. I wouldn't say that. I think enums and ordinal() have their uses, just not the use you were hoping for. In general, I think trying to make enums model any kind of external or customer data is a bad idea. Customer data always changes, and enums don't, without a lot of hassle. > Can someone think of a better way to do this, that doesn't repeat the > column values? Map<Integer,String>. Seriously. Set the strings and integers in a data or config file, or better yet read them from the scheme when needed. Then you'll always match the database, and you never have to go through the work of trying to figure out what to do if and when someone starts to modify the schema. public class DatabaseEnumeration { String table; String column; Map<Integer, String> intToEnum; Map<String, Integer> enumToInt; ... } Now you have the beginnings of a flexible class that can handle any table's enumerations and doesn't have all the unpleasant side effects associated with enums. You do loose some code constructs, like case statements, which you'll have to emulate with if-else chains, but that's not a lot to give up imo.
From: david.karr on 18 Dec 2009 20:17
On Dec 18, 4:25 pm, EJP <esmond.not.p...(a)not.bigpond.com> wrote: > david.karr wrote: > > Can someone think of a better way to do this, that doesn't repeat the > > column values? > > Have each enum value enter itself on construction into a Map<Integer, > YourEnum> with its own ColumnValue as the key. > > Like Peter I cannot see the point of setColumnValue(), and the Map would > of course require the columnValue to be constant. Yes, you're right, there's no need for "setColumnValue()". Concerning the Map, I had already thought of that. That's the obvious way to do it. Now, how would you do it? I would assume you'd define a static Map in the enum type and have the constructor put itself into the map. The problem is, it doesn't appear to be possible to do that. It doesn't compile. What might work is implementing some sort of "super-map" that holds all the mappings for all enum types you implement, so the key would have to concatenate the class and the custom ordinal. |