2010-06-09 14 views
20

Nous avons les classes suivantesComment obtenir le DiscriminatorValue au moment de l'exécution

@Entity 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) // optional annotation as this is default 
@DiscriminatorColumn(name = "apType", discriminatorType = DiscriminatorType.STRING, length = 255) 
@DiscriminatorValue("AP") 
public class ApplicationProcess { 
} 

Et ce

@Entity 
@DiscriminatorValue("APS") 
public class ApplicationProcessScheme extends ApplicationProcess { 
} 

Maintenant, je dois savoir à l'exécution si le ApplicationProcess est de DiscriminatorValueAP or APS. Puisqu'il est géré automatiquement par jpa, je n'ai aucun moyen d'obtenir cette valeur.

Nous appelons une méthode qui prend un ApplicationProcess comme paramètre, et je veux éviter d'utiliser instanceof pour vérifier de quel type il s'agit. Ce serait plus frais si je pouvais faire quelque chose comme

applicationProcess.getApType().equals("AP"); 

Répondre

34

Vous pouvez mapper votre discriminateur comme une propriété en lecture seule:

public class ApplicationProcess { 

    ... 

    @Column(name = "apType", insertable = false, updatable = false) 
    private String apType; 

} 
+0

@Shervin: Vous pouvez, mais ce n'est pas une bonne idée, votre logique ne devrait pas compter sur cette . –

+1

@Pascal: Je pense que je dois. Du côté xhtml, je n'ai aucun moyen dans l'expression EL de dire 'instanceof' (je pense). Donc je pourrais avoir besoin de ça. –

+1

@Shervin: Je suis désolé de le dire mais il semble que vous ayez une faille majeure dans votre conception, la ** vue ** ne devrait JAMAIS avoir à s'appuyer sur une valeur discriminante (ceci est vrai pour le code business mais encore plus pour la vue). –

5

Nous appelons une méthode qui prend un ApplicationProcess en tant que paramètre, et je veux éviter d'utiliser instanceof pour vérifier quel type il est. Ce serait plus frais si je pouvais faire quelque chose comme (...)

Je ne pense pas que ce serait plus frais, cela semble pire que d'appeler instanceOf pour moi: si, pour une raison quelconque vous modifiez la valeur discriminante, il casserait votre code. Si vous devez vérifier le type, utilisez instanceOf. Une astuce utilisant le discriminateur ne va pas rendre les choses plus agréables, cela rendrait votre code moins robuste.

+1

+1 Je suis totalement d'accord. Peut-être ce refactoring mon être applicable: http://www.c2.com/cgi/wiki?ReplaceConditionalWithPolymorphism –

+0

Mais alors je devrais faire quelque chose comme ceci: pseudo code: 'if (pas applicationProcess instanceof ApplicationProcessScheme)', parce que Je ne peux pas vérifier par rapport à ApplicationProcess puisque ApplicationProcessScheme correspondrait aussi à Donc le code serait 'if (obj instanceof ApplicationProcessScheme) {// car il n'y a pas! Instanceof} else {// Nous avons un enfant!}' –

+1

@Shervin: Oui, vous devriez le faire. Je ne dis pas que c'est idéal, je dis que se fier aux métadonnées serait pire. En fait, je creuserais la suggestion de Ash. –

29

Je peux imaginer quelques cas où il pourrait être utile, mais malgré la raison pour laquelle vous avez besoin de cela, vous pouvez créer votre classe abstraite méthode comme

@Transient 
public String getDiscriminatorValue(){ 
    DiscriminatorValue val = this.getClass().getAnnotation(DiscriminatorValue.class); 

    return val == null ? null : val.value(); 
} 
+1

Un cas d'utilisation peut être: une table de traduction pour tout le système avec des types (pays, langue, sexe, ...) et par type de clés multiples ("pl", "uk", "us", ...) et des valeurs ("Pologne", "Royaume-Uni", ...). Certains types peuvent être utilisés dans les relations '@ OneToMany', comme pays pourrait être utilisé dans une' Adresse @Entity ', mais d'autres types ne peuvent être utilisés qu'en interrogeant la base de données. Donc: la classe de base gérera la plupart des types, mais quelques uns spécifiques auront leur propre classe dérivée. – Arjan

+0

pour moi le problème avec la réponse acceptée était quand l'objected est juste créé et pas encore sauvé, discriminateur n'est pas présent. Dans les cas de test où les données ne sont pas vraiment persistantes à DB, j'ai eu des problèmes avec cela. Cela a bien fonctionné. Merci –

+0

Cela fonctionne très bien. –

0

Vous pouvez utiliser l'annotation de formule. Si vous utilisez Hibernate, vous pouvez utiliser le code ci-dessous selon this link:

private String theApType; 

@Formula("apType") 
String getTheApType() { 
    return theApType; 
} 

Bien sûr, vous pourrez l'utiliser dans vos requêtes.