通过 Criteria api 转义 LIKE 中的字符

问题描述 投票:0回答:2

我试图允许网络前端的用户搜索数据库中的某些属性。属性名称可能包含特殊的 SQL 字符 % 和 _,用于 like 中。有没有办法转义特殊字符?

我正在将 Criteria API 与 Glassfish 5.1、Apache Derby、JPA 2.1 和 EclipseLink 2.7.4 结合使用。

其他数据库使用 \ 作为默认转义字符,但 Derby 不使用。从阅读来看,严格的标准似乎要求没有隐式转义字符。

我用这个数据来说明:

ID           SETNAME             DESCRIPTION                                         
----------------------------------------------
1            Set_1               The very first set
2            Set%2               The second set

并且 SQL 通过 JDBC 直接连接到 Derby。这些表格是从以下实体生成的。

SELECT * FROM ATTRIBUTESETMETA WHERE SETNAME LIKE 'Set%2'

返回两行,如您所料(% = 通配符)。

我希望在 Criteria API 中复制以下内容

SELECT * FROM ATTRIBUTESETMETA WHERE SETNAME LIKE 'Set\%2' ESCAPE '\'

它只返回第一行,因为 \ 被显式设置为转义字符。

如果我使用

SELECT * FROM ATTRIBUTEMETA WHERE SETNAME LIKE 'Set\%2'

如果没有转义子句,我什么也得不到(与其他数据库不同)

这里是实体类和执行条件 api 查询的包装器。

/* Imports ... */
@Entity
public class AttributeSetMeta implements Serializable {
    private static final long serialVersionUID = 3L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String setName;
    private String description;

// Getters and setters ...
// Imports
@Dependent
public class AttributeSetMetaFacade {

    @PersistenceContext(unitName = "oms")
    private EntityManager em;

    public AttributeSetMeatFacade() {
    }

    public List<AttributeSetMeta> getSetByName(String name) {
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<AttributeSetMeta> cq = 
                cb.createQuery(AttributeSetMeta.class);
        Root<AttributeSetMeta> set = cq.from(AttributeSetMeta.class);
        cq.select(set)
                .where(cb.like(
                    set.get(AttributeSetMeta_.setName), name)
                );
        return em.createQuery(cq).getResultList();
    }

// Other code ...

该代码相当于我的第一个 SQL 查询并返回相同的结果。

有什么方法可以更改代码以使其表现得像我的第二个查询吗? (双关语)

java jpa derby criteria-api
2个回答
10
投票

在JPA中,

CriteriaBuilder
like
方法有几个重载,它们有第三个参数,即转义字符。它可以是
char
Expression<Character>
类型。

因此,对于您的情况,最简单的方法是这样:

cb.like(set.get(AttributeSetMeta_.setName), name, '\\')

相关API参考:


0
投票

我遇到了同样的问题,我使用 EscapeCharacter 通过包装像

这样的值来解决它
searchKey = EscapeCharacter.DEFAULT.escape(searchKey)
© www.soinside.com 2019 - 2024. All rights reserved.