JPA2标准不区分口音,不依赖于数据库



我使用JPA2中的本机查询来搜索与大小写或重音无关的特定文本(基于http://www.guj.com.br/java/212706-accent-insensitive-hibernate):

)
public List<Hipotesis> findHipotesisByText(String srchtext) {
    EntityManager em = getEntityManager();
    String textNormalized =
        Normalizer.normalize(srchtext, Normalizer.Form.NFD).replaceAll("[^\p{ASCII}]", "").toUpperCase();
    Query query =
        em.createNativeQuery(
            "select * from HIPOTESIS where ( UPPER(TRANSLATE( TEXTFIELD,'ÀÁÂÃáàâãÉÈÊéèêÍíÓÒÔÕóòôõÚÜúü','AAAAaaaaEEEeeeIiOOOOooooUUuu' ) ) like '%" + textNormalized + "%'",
            Hipotesis.class);
    @SuppressWarnings("unchecked")
    List<Hipotesis> results = query.getResultList();
    return results;
}

搜索文本被规范化为条带重音并转换为大写。本机查询使用TRANSLATE将重音转换为纯文本,而UPPER将结果转换为大写。

因此,搜索文本eMeRgÊ将被规范化为EMERGE,并将匹配数据库中的任何出现,如emergencia, emergência, Emergência。

虽然TRANSLATE是由SQL99指定的,但它不被完全支持或实现。

问题:有没有办法实现这个查询不使用翻译?或者不使用本机查询?

在我个人看来,最优雅的解决方案是实际复制数据并将其转换为规范化形式。您在查询中使用了LIKE条件,这基本上排除了任何正常的(全文除外)索引机制。这意味着TRANSLATE查询很可能效率低下,难以优化。

使用JPA,您可以使用实体生命周期事件以一种相当方便的方式管理规范化表单:

@Entity
public class Whatever implements Serializable {
    private static final long serialVersionUID = 0L;
    private String string;
    private String normalizedString;
    // getters and setters
    @PreUpdate
    @PrePersist
    protected void normalize() {
        normalizedString = yourNormalizationMethod(string);
    }
}

我相信这是解决这类问题的最干净、最优雅、最与数据库无关的方法。

最新更新