Eclipselink:使用定制器添加Where-Clause

时间:2017-10-09 08:34:04

标签: java jpa eclipselink

在我目前的项目中,我们将对数据库实体的nls支持进行折射。在我们之前的版本中,我们使用了会话语言,但不幸的是,这种行为并不完全稳定。因此我们将更改代码,以便将语言信息存储在查询中。 我希望有一个中心实例来处理这种语言行为,而不是在整个项目中的每个实体中更改每个查询。

E.g。我有这个实体:

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

现在有一种可能性是将n.nlsBackenKey.language = :locale添加到每个NamedQuery并更改每个调用,其中引用了此NamedQuery

更有利的方法是,Customizer添加区域设置参数。我有这个:

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

我将其添加到NLSBackendEntity@Customizer(QueryLanguageCustomizer.class)

但是现在,我无法设置此参数。再一次,我最喜欢的方式是使用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
    }

}

不幸的是,无论我尝试什么,我都无法设置此参数。 getTransaltionRow()返回null,我尝试过的所有其他可能性都失败了。

是否有可能在preExecuteQuery块内设置此参数?

我正在使用Eclipselink 2.5,非常感谢任何帮助

2 个答案:

答案 0 :(得分:0)

如果您不介意使用特定于供应商的解决方案,则可以使用EclipseLink @AdditionalCriteria注释。您可以按如下方式使用它:

  • 创建一个抽象映射类并从中派生所有实体:

    @MappedSuperclass
    @AdditionalCriteria("this.language = :lang")
    public class AbstractEntity {
    
        private String language;
    
        // getters + setters
    }
    
  • 让您的实体将其子类化:

    public class NLSBackendEntity extends AbstractEntity implements Serializable {
       // ...
    }
    
  • 在实体管理器或实体管理器工厂中设置language属性的值:

    entityManager.setProperty("language", "de"); 
    
在执行查询之前

。 EclipseLink应将language = ?附加到查询的where条件,以绑定您在实体管理器上设置的值。

答案 1 :(得分:0)

您可以使用ThreadLocal<String> threadProps = new ThreadLocal<String>();,将其设置为数据或恢复工厂类并在代码中使用。

如果您未在函数中创建任何新的其他线程,则上述解决方案将起作用。

您可以使用threadProps.get();

代替参数