2010-09-03 4 views

Répondre

2

À ma connaissance, il est impossible avec les annotations:

  • valeur discriminante doit être de type String
  • valeur discriminante doit être une compilation constante de temps, à savoir les valeurs de retour des méthodes sur énumérations sont interdit.
+0

JPA 2.1 n'a pas changé cela? –

+0

Ce n'est pas JPA, le langage Java ne vous permet pas d'appeler des méthodes pour les valeurs d'annotation, voir: http://docs.oracle.com/javase/specs/jls/se7/html/jls-9.html#jls-9.7 en 9.7.1, lire la liste: "Le type de' V' est compatible avec l'assignation (§5.2) avec 'T', et de plus:". Donc 'MyEnum.ENUM_CONST.x()' est invalide, 'MyEnum.ENUM_CONST' serait valide, mais' T' est 'String' ici. – TWiStErRob

2

yup, lorsque vous définissez discriminateur l'option de l'annotation sont nom et discrimatorType

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

dont DiscriminatorType ne peut être:

DiscriminatorType.STRING 
DiscriminatorType.CHAR 
DiscriminatorType.INTEGER 

malheureux je ne voyais pas hier, mais bien . C'est comme ça

+3

Et notez que 'DiscriminatorType' fait référence au type de base de données et non au type Java. 'DiscriminatorValue' doit toujours avoir un nombre entre guillemets sous forme de chaîne. – TWiStErRob

6

Non, malheureusement vous ne pouvez pas. Si vous essayez d'utiliser une valeur enum discriminator, vous obtiendrez une exception d'incompatibilité de type ("impossible de convertir MyEnum en String"), car les seuls types de discriminateurs autorisés sont String, Char et Integer. Ensuite, j'ai essayé d'utiliser un nom d'enum et un ordinal combinés avec DiscriminatorType.STRING et DiscriminatorType.INTEGER, respectivement. Mais cela ne fonctionne pas non plus, comme l'annotation @DiscriminatorValue (comme tout autre) nécessite une expression constante:

Cela ne fonctionne pas:

@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 
} 

ne fonctionne pas non plus:

@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

Vous pouvez utiliser DiscriminatorType.INTEGER et mapper chaque sous-classe avec @DiscriminatorValue("X"), où X doit être la valeur ordinale de l'énumération (0,1,2,3 ...).

doit doit être la valeur comme une constante Chaîne. Vous ne pouvez pas utiliser YourEnum.SOME_VALUE.ordinal(), car les valeurs d'attribut d'annotation doivent être des constantes. Oui, c'est fastidieux. Oui, il est sujet aux erreurs. Mais ça fonctionne.

+0

Il s'agit d'une solution de contournement hacky, mais cela fonctionne, je mettrais des commentaires énormes dans un 'enum' qui est utilisé comme un' DiscriminatorValue'! De même, la même chose fonctionne avec les noms enum (avec 'DiscriminatorType.String' qui peut être plus stable que l'ordinal. – TWiStErRob

23

Si vous essayez de ne pas dupliquer les valeurs du discriminateur, il existe une solution de contournement 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"; 
    } 
} 

Pas super élégant, mais mieux que d'avoir à maintenir les valeurs à plusieurs endroits.

13

Je voulais juste améliorer la bonne réponse de @asa à propos de la solution de contournement. Habituellement, nous aimons souvent utiliser la colonne discriminante comme un attribut de la classe abstraite, et mappé avec un enum bien sûr. Nous pouvons toujours utiliser la solution mentionnée ci-dessus et forcer certaines consistances entre enum noms (utilisés pour mapper la colonne) et String valeurs (utilisées comme valeurs discriminantes).Voici ma suggestion:

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

Et pour les entités, voici le code:

@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 { 
    … 
} 

pas encore parfait, mais un peu mieux, je pense.

Questions connexes