我在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,并将匹配数据库中出现的任何紧急情况,例如emergecia,emergência,Emergência。

尽管SQL99指定了TRANSLATE,但它并不完全像标准一样支持或实现。

问题:不使用TRANSLATE可以实现该查询吗?还是不使用本机查询?

最佳答案

我个人认为,最优雅的解决方案是实际复制数据并将其转换为规范化形式。您在查询中使用了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);
    }
}

我认为这是解决此类问题的最简洁,最优雅,最不了解数据库的方法。

07-24 09:17