Hibernate配置many-to-one not-found=ignore后Criteria查询报错的解决咨询
数据表中存在指向不存在记录的关联,为了提取带有断链的对象,在Hibernate映射文件中为many-to-one配置了not-found="ignore",配置代码如下:
<class name="pattern" table="PATTERN"> <id name="un" type="long"> <column name="UN" precision="10" scale="0" /> <generator class="native"/> </id> <many-to-one class="Workplace" fetch="select" lazy="false" name="workplace" not-found="ignore"> <column name="UN" not-null="true"/> </many-to-one> ... </class> <class name="Workplace" table="WORKPLACE"> <id name="un" type="long"> <column name="UN" precision="10" scale="0" /> <generator class="assigned"/> </id> ... </class>
此时可成功获取对象,但使用Criteria添加Restrictions.eq("workplace.un", un)查询时,出现错误:
could not resolve property: workplace.un of: pattern at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:285) at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:230) at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:551) at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:152) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) at
若移除not-found="ignore",查询正常但无法获取带断链的对象,请问能否修复该查询问题?
可以修复,核心原因是not-found="ignore"会让Hibernate在关联对象不存在时将workplace设为null,但使用Criteria查询workplace.un时,Hibernate会尝试解析关联属性的路径,当workplace为null时就会报错。这里提供几种可行的解决办法:
直接关联数据库字段查询
既然pattern表中存储关联的是WORKPLACE的UN字段,直接用该字段做查询条件即可,不需要通过关联对象的属性。把Restrictions.eq("workplace.un", un)改成Restrictions.eq("UN", un)(直接用数据库列名,若有表名冲突可加上表别名,比如p.UN)。使用SQLQuery替代Criteria
直接写原生SQL查询,绕开Hibernate的关联属性解析问题。示例:SELECT p.* FROM PATTERN p WHERE p.UN = :un通过
createSQLQuery执行后,将结果转换为Pattern对象即可。添加独立字段映射
在Pattern类中新增一个对应关联列的属性(比如workplaceUn),并在映射文件中配置单独的<property>标签:<property name="workplaceUn" column="UN" type="long"/>之后用
Restrictions.eq("workplaceUn", un)查询,同时保留many-to-one的not-found="ignore"配置,既能获取带断链的对象,又能正常执行查询。用DetachedCriteria处理关联与null场景
如果坚持用Criteria关联查询,可以通过DetachedCriteria同时处理关联存在和workplace为null的情况:Criteria criteria = session.createCriteria(Pattern.class); // 关联存在的情况 DetachedCriteria workplaceSubQuery = DetachedCriteria.forClass(Workplace.class) .add(Restrictions.eq("un", un)) .setProjection(Projections.id()); // 组合条件:关联存在 或者 关联为null(断链对象) criteria.add(Restrictions.or( Restrictions.isNull("workplace"), Subqueries.propertyIn("workplace.un", workplaceSubQuery) ));这种方式相对复杂,适合必须用Criteria的场景。
内容的提问来源于stack exchange,提问作者Vasiliy Volk

