使用 Hibernate Criteria 过滤 Map 中的键和值
Posted
技术标签:
【中文标题】使用 Hibernate Criteria 过滤 Map 中的键和值【英文标题】:Use Hibernate Criteria for filtering keys and values in Map 【发布时间】:2016-12-26 21:46:27 【问题描述】:我有以下持久类:
public class Code
@ElementCollection(targetClass = CodeValue.class)
@MapKeyClass(CodeProperty.class)
@JoinTable(name="code_properties")
@CreateIfNull( value = false )
private Map<CodeProperty,CodeValue> propertiesMap =
new HashMap<CodeProperty, CodeValue>();
...
public class CodeProperty
private String name;
...
public class CodeValue
private String value;
...
我正在尝试获取由 propertiesMap 中的一些属性过滤的代码列表(例如,名为“color”的属性的值为“green”的代码。
我使用以下基本标准:
Criteria criteria = currentSession()
.createCriteria(Code.class, "code")
.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
当我尝试执行收集过滤器时(建议 here):
criteria.createAlias("code.properties", "p");
criteria.add(Restrictions.eq("p.foo", "test1"));
criteria.setFetchMode("code.properties", FetchMode.JOIN);
criteria.list();
我收到以下错误:
org.hibernate.QueryException: could not resolve property: foo of: com.example.CodeValue
这意味着,我真的不明白为什么,hibernate 认为 code.properties 是 CodeValue 而不是 map !!!
我也尝试在不创建别名的情况下访问该字段,这样 hibernate 似乎可以访问正确的 Code 类。我使用了 properties.indeces(建议 here):
criteria.add(Restrictions.eq("properties.indeces", "foo"));
criteria.list();
但是这样我得到以下错误:
could not resolve property: properties.indeces of: com.example.Code
有人可以帮助我了解问题所在吗?找到绿色代码的正确条件查询是什么?
您可以结帐the Github project that demonstrates this problem。
谢谢
【问题讨论】:
我注意到您将 JPA 2.1 功能与 @MapKeyClass 一起使用。您是否一定要使用已弃用的 Hibernate Criteria API 而不是 JPA Criteria API? @Naros 代表 micdcar 回答 - 是的,不幸的是,这意味着将整个 sessionfactory 配置切换到 entitymanager,可以探索但不能在这么短的时间内进行。所以我们必须创建 Criteria,它返回休眠条件。 【参考方案1】:请确认您是否使用过索引或索引。正确用法如下:
criteria.createAlias("code.properties", "p");
criteria.add(Restrictions.eq("p.indices", "foo"));
criteria.list();
或者,您可以使用
eq("p." + CollectionPropertyNames.COLLECTION_INDICES)
在限制中。
如果它仍然不适合你,请告诉我。
【讨论】:
【参考方案2】:这可能不是您所期望的,但在更高版本的 hibernate 中,别名没有得到解决我在使用别名引用时在 Projections 中遇到问题 https://***.com/questions/36607042/hibernate-criteria-query-using-projections-aggregate-function-alias-throws-sette
【讨论】:
【参考方案3】:您的方法存在各种问题: 在您的项目 github 中查看 MapTest 文件夹,我可以建议您始终将变量名称为列名,并在 Criteria.xml 中使用相同的名称。 Criteria 是映射,其第一个参数是属性名称,第二个参数是属性的值。 对于多对多关系,您可以尝试使用:
@JoinTable(
name="docente_classe",
joinColumns=
@JoinColumn(name="id_dipendente", referencedColumnName="id_dipendente"),
inverseJoinColumns=
@JoinColumn(name="id_classe", referencedColumnName="id_classe")
)
这是JPA注解,不知道你的项目能不能编译。
https://github.com/tredue1/School_Manager/blob/master/code/SM/src/main/java/agc2/it/sm/gestioneDocente/DocenteJpa.java
关于多对多关系的查询请看这篇文章:
jpa criteria for many to many relationship 。
【讨论】:
对不起,我没有关注。您的示例没有任何地图。查询通过 Sets 实现的多对多是另一回事。您能否使用 GitHub 示例(或项目分支)澄清您的答案? 您是否尝试检查链接:***.com/questions/8135612/… ????这是一个很好的例子。【参考方案4】:我不相信您可以使用传统的 Hibernate Criteria API 做到这一点,并且使用 JPA 标准 API 的 Hibernate 实现存在一个小的限制。解决此问题的一种方法是:
通过直接使用谓词要求查询该实体来获取List<CodeProperty>
。
List<CodeProperty> propertyKeys = entityManager
.createQuery( "FROM CodeProperty p WHERE p.name = :name" )
.setParameter( "name", "foo" )
.getResultList();
使用 JPA 标准查询您的 Code
实体。
// setup the query
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Code> query = cb.createQuery( Code.class );
Root<Code> root = query.from( Code.class );
MapJoin<Code, CodeProperty, CodeValue> mapRoot = root.joinMap( "propertiesMap" );
query.select( root ).where( mapRoot.key().in( propertyKeys ) );
// get results
List<Code> results = entityManager.createQuery( query ).getResultList();
我尝试将这些组合使用:
query
.select( root )
.where ( cb.eq( mapRoot.key().get( "name" ), "foo" ) )
问题是这会导致NotYetImplemented
异常:(。
【讨论】:
问题是,OP 的问题是关于非实体查询。此外,用 JPA 查询替换 Hibernate Classic Criteria 查询往往会强制更改整个持久性实现(从 SessionFactory 到 EntityManager),这比它的价值要麻烦得多。 @Gwaptiva 理解,但我相信这是用户在从 Hibernate 5 升级到 6 时需要考虑的不可避免的变化。 公平点。我想我可能一直在预测我自己对我的应用程序中的这种变化的恐惧:(以上是关于使用 Hibernate Criteria 过滤 Map 中的键和值的主要内容,如果未能解决你的问题,请参考以下文章
Hibernate Criteria API 中的 SQL 'LIKE' 运算符
使用 Hibernate 的 Criteria 和 Projections 选择多个不同的列