简体   繁体   中英

Eclipselink: Adding Where-Clause using customizer

In my current project, we will refractor the nls-support for database entities. In our previous version, we used the session language, but unfortualy this behaviour was not completely stable. So we will change the code, so that the language information is stored inside the query. I would love to have a central instance to handle this language behaviour instead of changing each query, in every entity spread over the whole project.

Eg I have this entity:

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

One possibility would now be to add the n.nlsBackenKey.language = :locale to every NamedQuery and to change every call, where this NamedQuery is referenced.

A more favorable way would be, to have a Customizer to add the locale paramter. Atm I have this:

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

And I added this to the NLSBackendEntity : @Customizer(QueryLanguageCustomizer.class)

But now, I'm not able to set this parameter. Again, my favored way, would be to use a 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
    }

}

Unfortunatly no matter what I try, I'm unable to set this parameter. The getTransaltionRow() returns null , and every other possibility I tried failed.

Are there no possibilitys to set this parameter inside the preExecuteQuery block?

I'm using Eclipselink 2.5, any help is highly appreciated

If you don't mind using vendor-specific solution you could use EclipseLink @AdditionalCriteria annotation. You could use it as follows:

  • Create an abstract mapped class and derive all entities from it:

     @MappedSuperclass @AdditionalCriteria("this.language = :lang") public class AbstractEntity { private String language; // getters + setters }
  • Let your entities subclass it:

     public class NLSBackendEntity extends AbstractEntity implements Serializable { // ... }
  • Set the value of language property on either the entity manager or entity manager factory:

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

before the queries are executed. EclipseLink should append language = ? to the where condition of your query binding the value you set on the entity manager.

You can use ThreadLocal<String> threadProps = new ThreadLocal<String>(); which you can set it on data or rest factory class and use it in your code.

The above solution will work if you not creating any new additional thread inside your functions.

Instead of parameter you can use threadProps.get();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM