我一直在使用JPA1.0( Hibernate驱动程序)中的Hibernate限制。有定义的Restrictions.ilike("column","keyword", MatchMode.ANYWHERE)
,它测试关键字是否匹配列在任何地方,它是不区分大小写的。
现在,我使用带有EclipseLink的JPA2.0作为驱动程序,所以我必须使用内置的“限制”JPA2.0。我找到了CriteriaBuilder
和like
方法,我还发现了如何使它在任何地方匹配(尽管它是令人敬畏和手动的),但我仍然没有弄清楚如何做到大小写不敏感。
这是我目前令人敬畏的解决办法:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<User> query = builder.createQuery(User.class);
EntityType<User> type = em.getMetamodel().entity(User.class);
Root<User> root = query.from(User.class);
// Where
// important passage of code for question
query.where(builder.or(builder.like(root.get(type.getDeclaredSingularAttribute("username", String.class)), "%" + keyword + "%"),
builder.like(root.get(type.getDeclaredSingularAttribute("firstname", String.class)), "%" + keyword + "%"),
builder.like(root.get(type.getDeclaredSingularAttribute("lastname", String.class)), "%" + keyword + "%")
));
// Order By
query.orderBy(builder.asc(root.get("lastname")),
builder.asc(root.get("firstname")));
// Execute
return em.createQuery(query).
setMaxResults(PAGE_SIZE + 1).
setFirstResult((page - 1) * PAGE_SIZE).
getResultList();
问题:
是否有类似于Hibernate驱动程序的功能?
我是否正确地使用了JPA2.0标准?与Hibernate限制相比,这是一种尴尬和不舒服的解决方案。
或者谁能帮我改变我的解决方案,使之不区分大小写,拜托?
非常感谢。
发布于 2011-01-04 08:02:34
一开始它看起来有点尴尬,但它是类型安全的。从字符串构建查询不是这样,所以您在运行时而不是在编译时注意到错误。您可以通过使用缩进或单独执行每一步来提高查询的可读性,而不是在一行中写入整个WHERE子句。
要使查询不区分大小写,请将关键字和比较字段转换为小写:
query.where(
builder.or(
builder.like(
builder.lower(
root.get(
type.getDeclaredSingularAttribute("username", String.class)
)
), "%" + keyword.toLowerCase() + "%"
),
builder.like(
builder.lower(
root.get(
type.getDeclaredSingularAttribute("firstname", String.class)
)
), "%" + keyword.toLowerCase() + "%"
),
builder.like(
builder.lower(
root.get(
type.getDeclaredSingularAttribute("lastname", String.class)
)
), "%" + keyword.toLowerCase() + "%"
)
)
);
发布于 2017-11-24 16:58:36
正如我在(当前)接受的答案中所评论的那样,一方面使用DBMS的lower()
函数,另一方面使用java的String.toLowerCase()
,因为这两种方法都不适合为相同的输入字符串提供相同的输出。
我终于找到了一个更安全(但不是防弹的)解决方案,即让DBMS使用一个文字表达式执行所有的降低操作:
builder.lower(builder.literal("%" + keyword + "%")
因此,完整的解决方案应该是:
query.where(
builder.or(
builder.like(
builder.lower(
root.get(
type.getDeclaredSingularAttribute("username", String.class)
)
), builder.lower(builder.literal("%" + keyword + "%")
),
builder.like(
builder.lower(
root.get(
type.getDeclaredSingularAttribute("firstname", String.class)
)
), builder.lower(builder.literal("%" + keyword + "%")
),
builder.like(
builder.lower(
root.get(
type.getDeclaredSingularAttribute("lastname", String.class)
)
), builder.lower(builder.literal("%" + keyword + "%")
)
)
);
编辑:
正如@cavpollo要求我举个例子一样,我不得不再三考虑我的解决方案,并意识到它并不比公认的答案安全得多:
DB value* | keyword | accepted answer | my answer
------------------------------------------------
elie | ELIE | match | match
Élie | Élie | no match | match
Élie | élie | no match | no match
élie | Élie | match | no match
尽管如此,我还是更喜欢我的解决方案,因为它不会将结果与两种不同的功能进行比较,这两种功能应该是相同的。我将相同的函数应用于所有字符数组,以便比较输出更加“稳定”。
防弹解决方案将涉及区域设置,从而使SQL的lower()
能够正确地降低重音字符。(但这超出了我所知的范围)
*Db值与带有'C‘语言环境的PostgreSQL 9.5.1
发布于 2014-05-07 13:22:03
这是我的工作:
CriteriaBuilder critBuilder = em.getCriteriaBuilder();
CriteriaQuery<CtfLibrary> critQ = critBuilder.createQuery(Users.class);
Root<CtfLibrary> root = critQ.from(Users.class);
Expression<String> path = root.get("lastName");
Expression<String> upper =critBuilder.upper(path);
Predicate ctfPredicate = critBuilder.like(upper,"%stringToFind%");
critQ.where(critBuilder.and(ctfPredicate));
em.createQuery(critQ.select(root)).getResultList();
https://stackoverflow.com/questions/4580285
复制相似问题