2010-09-03 28 views

Respuesta

2

Que yo sepa, esto no es posible con las anotaciones:

  • valor discriminador tiene que ser de String
  • valor discriminador debe ser un tiempo de compilación constante, es decir, valores de retorno de métodos en las enumeraciones son No permitido.
+0

JPA 2.1 no ha cambiado esto? –

+0

No es APP, el lenguaje Java no permite que llame a métodos para valores de anotación, consulte: http://docs.oracle.com/javase/specs/jls/se7/html/jls-9.html#jls-9.7 en 9.7.1, lea la lista: "El tipo de' V' es compatible con la asignación (§5.2) con 'T', y además:". Entonces 'MyEnum.ENUM_CONST.x()' no es válido, 'MyEnum.ENUM_CONST' sería válido, pero' T' es 'String' aquí. – TWiStErRob

2

Sí, cuando se define discriminador opción de la anotación son nombre y discrimatorType

@DiscriminatorColumn (name="MYDISCRIMINATOR", discriminatorType= DiscriminatorType.INTEGER) 

de los cuales DiscriminatorType sólo pueden ser:

DiscriminatorType.STRING 
DiscriminatorType.CHAR 
DiscriminatorType.INTEGER 

desafortunado que no vieron esto ayer, pero bien . Así es

+3

Y tenga en cuenta que 'DiscriminatorType' hace referencia al tipo de base de datos y no al tipo de Java. 'DiscriminatorValue' debe tener un número entre comillas como String. – TWiStErRob

6

No, desafortunadamente no se puede.

Si intenta utilizar una enumeración como valor discriminador, obtendrá una excepción de Tipo no coincidente ("no se puede convertir de MyEnum a Cadena"), ya que los únicos tipos de discriminador permitidos son Cadena, Carácter y Entero. A continuación, intenté usar el nombre y el ordinal de una enumeración combinados con DiscriminatorType.STRING y DiscriminatorType.INTEGER, respectivamente. Pero esto no funcionaba bien, como la anotación @DiscriminatorValue (como cualquier otra) requiere una expresión constante:

esto no funciona:

@Entity 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name="FREQUENCY", 
    discriminatorType=DiscriminatorType.STRING 
)  
public abstract class Event {} 

@Entity 
@DiscriminatorValue(value=Frequency.WEEKLY.name()) 
public class WeeklyEvent extends Event { 
    // Exception: The value for annotation attribute DiscriminatorValue.value must be a constant expression 
} 

No funciona bien:

@Entity 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name="FREQUENCY", 
    discriminatorType=DiscriminatorType.INTEGER 
) 
public abstract class Event {} 

@Entity 
@DiscriminatorValue(value=Frequency.WEEKLY.ordinal()) 
public class WeeklyEvent extends Event { 
    // Exception: The value for annotation attribute DiscriminatorValue.value must be a constant expression 
} 
1

Puede usar DiscriminatorType.INTEGER, y asignar cada subclase a @DiscriminatorValue("X"), donde X debe ser el valor ordinal de la enumeración (0,1,2,3 ...).

Es debe ser el valor como una cadena constante. No puede usar YourEnum.SOME_VALUE.ordinal(), porque los valores de los atributos de anotación deben ser constantes. Sí, es tedioso. Sí, es propenso a errores. Pero funciona.

+0

Esta es una solución hacky, sin embargo, funciona, pondría enormes comentarios en un 'enum' que se utiliza como un' DiscriminatorValue'! También lo mismo funciona con nombres enum (con 'DiscriminatorType.String' que puede ser más estable que el ordinal. – TWiStErRob

23

Si lo que intenta lograr es no duplicar los valores del discriminador, existe una solución simple.

@Entity 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name="FREQUENCY", 
    discriminatorType=DiscriminatorType.STRING 
)  
public abstract class Event { 
} 

@Entity 
@DiscriminatorValue(value=Frequency.Values.WEEKLY) 
public class WeeklyEvent extends Event { 
    … 
} 

public enum Frequency { 
    DAILY(Values.DAILY), 
    WEEKLY(Values.WEEKLY), 
    MONTHLY(Values.MONTHLY); 

    private String value; 

    … 

    public static class Values { 
     public static final String DAILY = "D"; 
     public static final String WEEKLY = "W"; 
     public static final String MONTHLY = "M"; 
    } 
} 

No es muy elegante, pero es mejor que tener que mantener los valores en varios lugares.

13

Solo quería mejorar la excelente respuesta de @asa sobre la solución. Por lo general, a menudo nos gusta utilizar la columna de discriminador como un atributo de la clase abstracta, y mapeamos con un enum, por supuesto. Todavía podemos utilizar la solución mencionada anteriormente y forzar algunas consistencias entre los nombres enum (utilizados para asignar la columna) y los valores String (utilizados como valores del discriminador).Aquí está mi sugerencia:

public enum ELanguage { 
    JAVA(Values.JAVA), GROOVY(Values.GROOVY); 

    private ELanguage (String val) { 
    // force equality between name of enum instance, and value of constant 
    if (!this.name().equals(val)) 
     throw new IllegalArgumentException("Incorrect use of ELanguage"); 
    } 

    public static class Values { 
    public static final String JAVA= "JAVA"; 
    public static final String GROOVY= "GROOVY"; 
    } 
} 

Y para las entidades, aquí está el código:

@Entity 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name="LANGUAGE_TYPE", discriminatorType=DiscriminatorType.STRING)  
public abstract class Snippet { 
    // update/insert is managed by discriminator mechanics 
    @Column(name = "LANGUAGE_TYPE", nullable = false, insertable = false, updatable = false) 
    @Enumerated(EnumType.STRING) 
    public ELanguage languageType 
} 

@Entity 
@DiscriminatorValue(value=ELanguage.Values.JAVA) 
public class JavaSnippet extends Snippet { 
    … 
} 

aún no es perfecto, pero un poco mejor, creo.

Cuestiones relacionadas