【问题标题】:Create dynamic hibernate criteria query with subcriteria使用子条件创建动态休眠条件查询
【发布时间】:2026-01-14 16:05:02
【问题描述】:

我有一个 Java 类,它有一些用@SearchCriteria(criteria = "class1.class2.field") 注释的字段。 criteria参数里面注解意味着对于class这个字段应该设置为休眠条件,这意味着,如果字段标记例如:

@SearchCriteria(criteria = "class1.class2.field")
private String value;

我想动态创建看起来像的休眠条件

DetachedCriteria hibernateCriteria = forClass(Class.class);
hibernateCriteria.createCriteria("class1").createCriteria("class2").add(eq("field", value));

问题是我不能设置另一个已经添加的标准,这意味着我应该检查注释criteria 选项。

      switch (annotationCriteria.length - 1) {
case 0:             
hibernateCriteria.add(isNull(annotationCriteria[0]));               
case 1:
hibernateCriteria.createCriteria(annotationCriteria[0]).add(                Restrictions.isNull(annotationCriteria[annotationCriteria.length - 1]));
case 2:   hibernateCriteria.createCriteria(annotationCriteria[0]).createCriteria(annotationCriteria[1]).add(                Restrictions.isNull(annotationCriteria[annotationCriteria.length - 1]));
    }

我想删除这个“开关”。有可能获得已经添加的标准,我现在没有,例如通过“名称”并为其添加新的子标准。

【问题讨论】:

    标签: hibernate spring detachedcriteria


    【解决方案1】:

    不,这是不可能的。 Detached Criteria API 不允许 - 无论好坏 - 允许发现,因此您将无法向其询问“现有”标准。

    但是,您可以做的是通过关联路径维护您自己的嵌套条件图。在伪代码中:

    Map<String, DetachedCriteria> criteriaMap = ...;
    
    for ( ) { // loop over annotation criteria's "elements"
        DetachedCriteria existing = criteriaMap.get(fullPath);
        if (existing==null) {
            existing = parentCriteria.createCriteria(pathElement);
            criteriaMap.put(fullPath, existing);
        }
        existing.add(whateverCondition);
    }
    

    【讨论】:

      【解决方案2】:

      我为这个问题找到了更多“好”的解决方案。 首先创建一些 searchCriteria 类,例如:

      public class SearchCriteria {
      
          @SearchCriteria(path = "someclass.someclass.id")
          private Integer someId;
      
          public Integer getSomeId() {
              return someId;
          }
      
          public void setSomeId(Integer someId) {
              this.someId= someId;
          }
      }
      

      以及自定义注解:

      @Target(value = { ElementType.FIELD })
      @Retention(RUNTIME)
      public @interface SearchCriteria {
          String path() default "";
      
          boolean optional() default true;
      }
      

      在 DAO 类中:

      @Override
          public Collection<SomeClass> find(SearchCriteria criteria) {
              DetachedCriteria hibernateCriteria = forClass(SomeClass.class);
      
              for (Field field : criteria.getClass().getDeclaredFields()) {
                  Annotation annotation = field.getAnnotation(SearchCriteria.class);
      
                  if (annotation == null) {
                      continue;
                  }
      
                  List<String> elements = Arrays.asList(StringUtils.split(((SearchCriteria) annotation).path(), "."));
      
                  field.setAccessible(true);
                  Object fieldValue = null;
                  try {
                      fieldValue = field.get(criteria);
                  } catch (IllegalArgumentException e) {
                      LOG.error("while trying to get private field value of entity " + SearchCriteria.class, e);
                  } catch (IllegalAccessException e) {
                      LOG.error("while trying to get private field value of entity " + SearchCriteria.class, e);
                  }
      
                  for (String element : elements) {
                      if (elements.indexOf(element) == elements.size() - 1) {
                          hibernateCriteria = hibernateCriteria.add(eq(element, fieldValue));
                      } else {
                          hibernateCriteria = hibernateCriteria.createCriteria(element);
                      }
                  }
              }
      
              return getHibernateTemplate().findByCriteria(hibernateCriteria);
          }
      

      【讨论】:

        最近更新 更多