New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
custom value mappings for @Enumerated #47
Comments
@glassfishrobot Commented |
@glassfishrobot Commented
|
@glassfishrobot Commented |
@glassfishrobot Commented So instead annotate the getCode() method like:
or
Another alternative would be to create an annotation that acts just like @XmlEnumValue does for xml mapping ... so create a @DbEnumValue such that:
|
@glassfishrobot Commented |
@glassfishrobot Commented
|
@glassfishrobot Commented |
@glassfishrobot Commented Example:
|
@glassfishrobot Commented The pattern above clearly keeps out the integration (JPA) from the model code. This is very important when the Enum is part of a public API (where no such dependency should be required), but this is not always everyone's goal. Sometimes Enums are dedicated to JPA ... or, as you said, you don't prefer to keep such a "pure" separation of concerns. |
@glassfishrobot Commented |
@glassfishrobot Commented Just for information purposes I have implemented this in my ORM. All that is required is to annotate the method used to return the value stored in the database (the getCode() method in the example below). For my ORM I use @DbEnumValue. The ORM loops the enum entries and builds its map of DB to Enum values to there is no need for anything else (no other annotations required etc). The original example becomes:
Note: The @DbEnumValue annotation has a storage() attribute that can be either DbEnumType.VARCHAR or DbEnumType.INTEGER. Cheers, Rob. |
@glassfishrobot Commented Our schemas tend to have FK constraints from data tables to "enum" tables that contain fixed control data. I don't even care if we have to write some boilerplate in the style that @pbenedict suggested above...that seems OK to me, but I'd like to add that any improvements to enum support should allow mapping an enum to these kinds of dedicated control data tables:
This still requires us to duplicate the control data values in the table as enum constants and keep the two in sync, but at least it gives us the strong typing of values found in the LANGUAGE_TYPE table. I think it could otherwise work like @pbenedict implies in his code sample. What would be really awesome is if the JPA provider could scan the table on startup and somehow update the enum constant code values with the data from the @EnumeratedColumn to avoid having to duplicate and hardcode the same values from the database table into in the Java enum type itself. I don't know if that last idea is possible due to how enum types are implemented in the first place. But, the provider could at least maintain an internal map of enum type constants to actual rows on a default enum.getCode() == LANGUAGE_TYPE.code policy so FK column updates could occur correctly when an entity property that is mapped to an @Enumerated type is changed. Regarding a point made by @jd3714att in the original issue description, some kind of optional name mapper could be specified to provide a different matching policy allowing the provider to handle dealing with values found in the target table that violate Java enum constant naming rules. |
@glassfishrobot Commented |
@glassfishrobot Commented |
@glassfishrobot Commented To support persistence of return value of method (on the enum, like above examples) it easily doable to extend the current @Enumerated to add a new EnumType and add an attribute for the method name (on the enum that will be persisted). That way you also can have XML specification of the method to use (rather than the above that only work with annotations, and not everybody thinks that's a "good idea"). @Enumerated(value=EnumType.METHOD, methodName="getCode") |
@glassfishrobot Commented |
|
So this very long discussion is quite old now, and doesn't seem to have ever reached much of a firm conclusion. As pointed out by others, there's quite a lot of overlap with So there's indeed a good case to me made for allowing explicit "remapping" of Just off the top of my head, I can think of two ways to do this. The first is the one that seems to have been proposed here: enum Status {
OPEN, CLOSED, CANCELLED;
@EnumeratedValue
int toInt() {
switch (this) {
case OPEN: return 0;
case CLOSED: return 1;
case CANCELLED: return -1;
default: throw new RuntimeException();
}
}
} The problem with this is it makes the enumerated values implicitly dynamic. There's no way to force But there's a different way, which was mentioned in this comment: enum Status {
@EnumeratedIntValue(0)
OPEN,
@EnumeratedIntValue(1)
CLOSED,
@EnumeratedIntValue(-1)
CANCELLED;
} That's shorter, and more "correct". It's the solution I've already proposed that we implement in Hibernate. The downside to this approach is that we would need two annotations ( Anyway, I think the second approach would be thing worth having in JPA. |
Well, excuse me, that was wrong: actually @jaguild above already proposed to stick the annotation on a enum Status {
OPEN(0), CLOSED(1), CANCELLED(-1);
@EnumeratedValue
final int intValue;
Status(int intValue) {
this.intValue = intValue;
}
} And that works too. The advantage is that only one annotation is needed; the disadvantage is that I need to add a field to my |
In #463 I propose this solution. I've also reworked the section on |
In mapping a pre-existing schema, it is rarely possible to map a given set of constants using an @Enumerated:
Limitation is because specification states the name() will be used of an enum.
A typical example: Database uses 'N/A', which can never be mapped to an enum. Intuition will let us look for a solution to map this to 'NOT_AVAILABLE', both a valid name for an Enum Constant, and also conventional naming.
On top of this, an enum often has a representation in the Database, and a constant has usually other additional attributes that could be useful.
Better than using the name() of an @Enumerated, we should map the enumerated similar as an @entity, and use the @id.
The text was updated successfully, but these errors were encountered: