如何将基于Map键值LIKE查询的@Query注解转为QueryDSL适配Hibernate6
问题解决
错误原因分析
- 第一个报错Parameter value [cro] did not match expected type [java.util.Map (n/a)]:你直接将
country.localizations集合属性传入字符串模板,该字段是Map类型,和字符串查询参数类型不匹配。 - 第二个报错Subquery returns more than 1 row:Hibernate 6 对
KEY()/VALUE()函数的处理逻辑做了调整,如果直接作用在集合属性上,会自动生成隐式子查询,单个国家对应多个本地化条目时就会触发多行子查询错误。
正确实现
核心逻辑是显式给join的Map条目声明别名,所有KEY/VALUE操作都针对该别名执行,和你原@Query里的loc别名逻辑完全一致:
import com.querydsl.core.types.dsl.MapEntryPath; import com.querydsl.core.types.dsl.Expressions; List<Country> findByFirstChars(String name) { QCountry country = QCountry.country; // 显式声明Map.Entry类型的别名,对应原@Query中的loc MapEntryPath<String, String> loc = Expressions.mapEntryPath(String.class, String.class, "loc"); String nameMatch = name.toLowerCase() + "%"; return new JPAQueryFactory(entityManager) .selectFrom(country) .distinct() // 绑定join关联到别名loc .leftJoin(country.localizations, loc).fetchJoin() .where( // 直接用别名的key方法匹配前缀,等价于KEY(loc) LIKE 'NAME%' loc.key().like("NAME%"), // 用别名的value方法做小写匹配,等价于LOWER(loc) LIKE LOWER(:name) loc.value().toLowerCase().like(nameMatch) ) .fetch(); }
补充说明
如果需要和原SQL写法完全对齐,也可以用字符串模板实现条件,只要传入的操作对象是别名loc即可,效果和上述写法一致:
BooleanExpression whereClause1 = Expressions.stringTemplate("KEY({0})", loc).like("NAME%"); BooleanExpression whereClause2 = Expressions.stringTemplate("LOWER({0})", loc.value()).like(nameMatch);
内容的提问来源于stack exchange,提问作者user1034461
相关产品推荐
相关产品推荐

