2017-10-09 12 views
1

Dans mon projet actuel, nous allons réfracter le support nls pour les entités de base de données. Dans notre version précédente, nous utilisions le langage de session, mais malheureusement ce comportement n'était pas complètement stable. Nous allons donc changer le code, de sorte que les informations de langue soient stockées dans la requête. J'aimerais avoir une instance centrale pour gérer ce comportement au lieu de changer chaque requête, dans chaque entité répartie sur l'ensemble du projet.Eclipselink: Ajout d'une clause Where à l'aide du personnaliseur

E.g. J'ai cette entité:

@NamedQueries({ 
@NamedQuery(name = NLSBackendEntity.findAll, 
      query = "select n from NLSBackendEntity n"), 
@NamedQuery(name = NLSBackendEntity.getById, 
      query = "select n from NLSBackendEntity n where n.nlsBackendKey.key = :key") }) 
@Entity 
@Table(name = "backend_key_al") 
public class NLSBackendEntity implements Serializable 
{ 
    private static final long serialVersionUID = 1L; 

    public static final String findAll = "NLSBackend.findAll"; 
    public static final String getById = "NLSBackend.getById"; 

    @EmbeddedId 
    private NLSBackendKey nlsBackendKey; 

    /** 
    * The text in the language. 
    */ 
    @Lob 
    @Column(name = "TEXT") 
    private String text; 

    NLSBackendEntity() 
    { 
     // no arg constructor needed for JPA 
    } 

    public String getKey() 
    { 
     return nlsBackendKey.key; 
    } 

    public String getLanguage() 
    { 
     return nlsBackendKey.language; 
    } 

    public String getText() 
    { 
     return text; 
    } 

    @Embeddable 
    public static class NLSBackendKey implements Serializable 
    { 
     private static final long serialVersionUID = 1L; 

     /** 
     * the NLS-key. 
     */ 
     @Column(name = "KEY") 
     private String key; 

     /** 
     * The language of this entry. 
     */ 
     @Column(name = "LOCALE") 
     private String language; 
    } 
} 

Une possibilité serait maintenant d'ajouter le n.nlsBackenKey.language = :locale à chaque NamedQuery et de changer chaque appel, où ce NamedQuery est référencé.

Un moyen plus favorable serait, d'avoir un Customizer pour ajouter le paramètre de locale. Atm J'ai ceci:

public class QueryLanguageCustomizer implements DescriptorCustomizer 
{ 

    @Override 
    public void customize(ClassDescriptor descriptor) throws Exception 
    { 
     ExpressionBuilder eb = new ExpressionBuilder(descriptor.getJavaClass()); 
     Expression languageExp = eb.getField("LOCALE").equal(eb.getParameter("locale")); 
     descriptor.getQueryManager().setAdditionalJoinExpression(languageExp); 
    } 
} 

Et j'ajouté à la NLSBackendEntity: @Customizer(QueryLanguageCustomizer.class)

Mais maintenant, je ne suis pas en mesure de régler ce paramètre. Encore une fois, ma façon privilégiée, serait d'utiliser un SessionEventAdapter:

public class LanguageSessionEventListener extends SessionEventAdapter { 
    /** Log for logging. */ 
    private static final Log LOG = LogFactory 
      .getLog(LanguageSessionEventListener.class); 

    @Override 
    public void preExecuteQuery(SessionEvent event) { 
     LOG.debug("preExecuteQuery called for session= " 
       + event.getSession().getName()); 
     event.getQuery().getTranslationRow().put("LOCALE", getLocale()); 
     super.preExecuteQuery(event); 
    } 

    private String getLocale() { 
     // uninteresting for this example 
    } 

} 

Malheureusement, peu importe ce que j'essaie, je suis incapable de définir ce paramètre. Le getTransaltionRow() renvoie null et toutes les autres possibilités que j'ai essayées ont échoué.

N'existe-t-il pas de possibilité de définir ce paramètre dans le bloc preExecuteQuery?

J'utilise EclipseLink 2.5, toute aide est très appréciée

Répondre

0

Si vous ne me dérange pas en utilisant une solution spécifique au fournisseur, vous pouvez utiliser l'annotation EclipseLink @AdditionalCriteria. Vous pouvez l'utiliser comme suit:

  • Créer une classe abstraite cartographié et d'en tirer toutes les entités de celui-ci:

    @MappedSuperclass 
    @AdditionalCriteria("this.language = :lang") 
    public class AbstractEntity { 
    
        private String language; 
    
        // getters + setters 
    } 
    
  • Laissez vos entités sous-classer:

    public class NLSBackendEntity extends AbstractEntity implements Serializable { 
        // ... 
    } 
    
  • Régler la valeur de la propriété language dans l'usine du gestionnaire d'entité ou du gestionnaire d'entité:

    entityManager.setProperty("language", "de"); 
    

avant l'exécution des requêtes. EclipseLink doit ajouter language = ? à la condition where de votre requête liant la valeur que vous avez définie dans le gestionnaire d'entités.

+0

J'ai aussi pensé à ça. Le problème est que la langue peut changer au cours de la durée de vie de l'EntityManager. Les états Eclipselink [ici] (http://www.eclipse.org/eclipselink/documentation/2.5/jpa/extensions/a_additionalcriteria.htm): "Ne pas modifier les propriétés pour la durée de vie du gestionnaire d'entités." –

+0

Eh bien, j'ai lu ça aussi.Mais je ne sais pas quel environnement vous utilisez; Si vous êtes dans un environnement JEE et que vous utilisez un gestionnaire d'entités à portée de transaction, la durée de vie du gestionnaire d'entités correspond à la portée de la méthode actuelle ou à la portée de la méthode qui a initié la transaction. Si votre configuration change dans cette étendue, cela ne vous aidera pas, je pense. – ujulu