hibernate标准过滤一组枚举值

时间:2010-06-03 15:06:29

标签: java sql mysql hibernate enums

您好我正在使用Hibernate 3.2和1.6 JDK以及Mysql 5.0我正在尝试使用标准api来组合动态过滤器。但是当我在一组枚举上添加一个限制时,我得到了一个org.hibernate.exception.GenericJDBCException。

我的代码是这样的:

public class FollowUp {
    ...
    public Set<AdminCategory> getAdminCategories() {...}
    public void setAdminCategories(Set<AdminCategory> _arg) { ... }

}

我的hibernate映射文件有一组在hibernate文档中指定的Enum值: http://docs.jboss.org/hibernate/stable/core/reference/en/html/collections.html#collections-ofvalues。该文件(FollowUp.hbm.xml )就像这样

<hibernate-mapping>
    <typedef class="dao.util.HibernateAdminCategoryType" name="main-category" />
    <class name="FollowUp" table="follow_up">
    <!-- other properties here -->
    <set name="mainCategories" table="follow_up_main_categories" fetch="join" lazy="false">
             <key column="fup_id"/>
             <element column="identifier" type="main-category"/>
     </set>
     <!-- other stuff -->
     </class>
</hibernate-mapping>

标准过滤器代码如下:

public void runFilter(FollowUpFilter _filter) {
    Criteria criteria = this.getSession().createCriteria(FollowUp.class);
    if (_filter.hasMainCategories()) {
        criteria.add(Restrictions.in("mainCategories", _filter.getMainCategories()));    
    }
    criteria.setResultTransformer( Criteria.DISTINCT_ROOT_ENTITY );

    criteria.setProjection(Projections.rowCount());
    Integer count = (Integer) criteria.uniqueResult();
    _filter.setTotalSize(count);
}

当我运行我的测试(使用sql输出)时,我收到以下错误:

Statement parameter 1 not set.
org.hibernate.exception.GenericJDBCException: could not execute query

sql输出如下:

select
    count(*) as y0_ 
from
    follow_up this_ 
where
    this_.id in (
        ?
    ) 

有没有人知道在条件中过滤一组枚举值的正确方法(在Hibernate 3.2中)?

干杯 西蒙

3 个答案:

答案 0 :(得分:1)

您似乎正在传递不兼容的参数类型。例如,它期望很长但你传递int。将您的日志级别设置为跟踪并查看hibernate期望的内容,以便您可以决定传递数组或集合或其他内容。

答案 1 :(得分:1)

我查看了几个不同的页面,包括以下内容:

包含这个看起来像是使用hibernate 3.5或JPA 2.0(带注释)的人的优雅解决方案:

Hibernate Criteria API - adding a criterion: string should be in collection

这个最终为我指出了一个解决方案: https://forum.hibernate.org/viewtopic.php?f=1&t=942839&start=0

最后我做了一个手动的subselect,我对它不满意但是它有效。我无法相信这是首选的解决方案,但我找不到任何其他解决方案。它就像解决方案一样丑陋而且仍然保证名称: - (

public void runFilter(AdminNoteFilter _filter) {
   assert _filter != null;
   Criteria criteria = this.getSession().createCriteria(FollowUp.class);
   if (_filter.hasMainCategories()) {
      CriteriaQueryTranslator cqt = null;

      Criterion mainCategoriesCriterion = HibernateFilterUtil.getEnumIdentifierCriterion(_filter.getMainCategories(),
         "{alias}.id in " +
         "(select fup.id " +
         "from follow_up fup, follow_up_main_categories v " +
         "where fup.id = v.fup_id and v.identifier in (" + HibernateFilterUtil.SUBSTITUE_QUESTION_MARKS + "))");
      criteria.add(mainCategoriesCriterion);

   }


   List<FollowUp> adminNotes = (List<FollowUp>) criteria.list();
}

/**
 * constructs a criterion for filtering on a collection of enums using a subselect.
 * <br />https://stackoverflow.com/questions/2967199/hibernate-criteria-filtering-on-a-set-of-enum-values
 * <br />https://forum.hibernate.org/viewtopic.php?f=1&t=942839&start=0
 *
 * @param _enums     non null non empty
 * @param _subSelect non null must contain the {@link #SUBSTITUE_QUESTION_MARKS} string to be substituted
 * @return the Criterion that can be added to a Criteria
 */
private static Criterion getEnumIdentifierCriterion(Set<? extends MarshallableEnum> _enums, String _subSelect) {
   assert _enums != null;
   assert _enums.size() > 0;
   assert _subSelect != null;
   assert _subSelect.contains(SUBSTITUE_QUESTION_MARKS);

   Set<String> identifiersSet = MarshallableEnumUtil.getIdentifiersFromMarshallableEnums(_enums);
   String[] identifiers = identifiersSet.toArray(Constants.EMPTY_STRING_ARRAY);

   // taken from
   //https://forum.hibernate.org/viewtopic.php?f=1&t=942839&start=0
   final org.hibernate.type.Type[] types = new org.hibernate.type.Type[identifiers.length];
   Arrays.fill(types, org.hibernate.Hibernate.STRING);

   final StringBuilder questionMarks = new StringBuilder();
   for (int i = 0; i < identifiers.length; i++) {
      if (i > 0) {
         questionMarks.append(",");
      }
      questionMarks.append("?");
   }
   // substitute in the question marks to the sub select subselect
   String finalSubSelect = _subSelect.replace(SUBSTITUE_QUESTION_MARKS, questionMarks);

   return Restrictions.sqlRestriction(finalSubSelect, identifiers, types);
}

private static Set<String> getIdentifiersFromMarshallableEnums(Set<? extends MarshallableEnum> _enums) {
   Set<String> retSet = new HashSet<String>();
   for (MarshallableEnum tmpEnum : _enums) {
      retSet.add(tmpEnum.getIdentifier());
   }
   return retSet;
}

希望这有帮助,如果你有人找到更好的hibernate(3.2)版本的解决方案,请发布它以帮助社区

干杯 西蒙

答案 2 :(得分:0)

我知道这是一个老问题,但我刚刚遇到了silimar问题并找到了解决方案。

您必须加入mainCategories并使用elements属性进行查询。就像那样:

session.createCriteria(FollowUp.class)
    .createAlias("mainCategories", "mainCategories")
    .add(Restrictions.eq("mainCategories.elements", Category.ITEM))
    .list()