如何根据特定订单订购hibernate的结果

时间:2015-07-07 23:33:22

标签: java hibernate hibernate-criteria

我需要发送一个查询来检索具有特定字符组的值,如下所示:

让我们说我对' XX'所以它应该搜索其值以' XX'或者有' XX' (空间XX)。例如XXCDEFPD XXRFCMKJIEK XX是有效结果。

我有以下查询 会返回正确的结果,但我需要对它们进行排序  以某种方式,它首先返回那些XX开头的那些结果。如下:

XXABCD
XXPLER
XXRFKF
AB XXAB
CD XXCD
ZZ XXOI
POLO XX

代码

Criteria criteria = session.createCriteria(Name.class, "name")
                .add(Restrictions.disjunction()
                     .add(Restrictions.ilike("name.fname", fname + "%"))
                     .add(Restrictions.ilike("name.fname", "%" + " " + fname + "%"))
                    )
                .setProjection(Projections.property("name.fname").as("fname"));
        List<String> names = (List<String>) criteria.list();

6 个答案:

答案 0 :(得分:21)

使用JPQL(HQL)

select fname from Name
where upper(fname) like :fnameStart or upper(fname) like :fnameMiddle
order by (case when upper(fname) like :fnameStart then 1 else 2 end), fname

query.setParameter("fnameStart", "XX%");
query.setParameter("fnameMiddle", "% XX%");

有条件

使用Criteria会更棘手。首先,您必须在order子句中使用本机SQL。其次,你必须绑定变量。

public class FirstNameOrder extends Order {
    public FirstNameOrder() {
        super("", true);
    }

    @Override
    public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
        return "case when upper(FIRST_NAME) like ? then 1 else 2 end";
    }
}

案例表达式语法和upper函数名称应根据您的数据库进行更改(当然,如果列名不同,则更改列名称。)

很容易将其添加到Criteria,但没有用于绑定参数的API。

我尝试通过将一个未使用的变量传递给自定义sql限制来欺骗Hibernate,以便它有效地用于order by子句中的变量:

Criteria criteria = session.createCriteria(Name.class, "name")
   .add(Restrictions.disjunction()
      .add(Restrictions.ilike("name.fname", fname + "%"))
      .add(Restrictions.ilike("name.fname", "%" + " " + fname + "%")))
   .setProjection(Projections.property("name.fname").as("fname"))
   .add(Restrictions.sqlRestriction("1 = 1", fname + "%", StringType.INSTANCE))
   .addOrder(new FirstNameOrder())
   .addOrder(Order.asc("fname"));

它工作正常。

显然,不建议使用此解决方案,我建议使用JPQL进行此查询。

答案 1 :(得分:3)

答案 2 :(得分:2)

运行两个选择,一个过滤所有以&#39; XX&#39;开头的字符串,第二个过滤为其他字符串。

答案 3 :(得分:1)

您可以在条件中使用谓词......类似这样的内容:

public List<Name> findByParameter(String key, String value, String orderKey)

            CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();
            CriteriaQuery<Name> criteria = builder.createQuery(this.getClazz());
            Root<Name> root = criteria.from(Name.getClass());
            criteria.select(root);
            List<Predicate> predicates = new ArrayList<Predicate>();
            predicates.add(builder.equal(root.get(key), value));
            criteria.where(predicates.toArray(new Predicate[predicates.size()]));
            if (orderKey!=null  && !orderKey.isEmpty()) {
                criteria.orderBy(builder.asc(root.get(orderKey)));
            }
            result = this.entityManager.createQuery(criteria).getResultList();

        return result;
}

答案 4 :(得分:0)

愚蠢,但它可能适合您的情况。

由于您得到了正确的结果,您可以按如下方式重建结果:

  1. 从XX开始拾取所有结果,将它们放入列表L1并按照Collections.sort(L1)进行正常排序;
  2. 对于所有其他结果,像Collections.sort(L2)一样执行L2列表
  3. 最后,把它们放在一起

    列出newList = new ArrayList(L1);

    newList.addAll(L2);

  4. 请注意。 Collections.sort遵循其元素的自然顺序。

答案 5 :(得分:0)

如果您不想在内存中对结果进行排序,可以修改条件,我会向您显示SQL

select * from table where fname like 'XX%' order by fname
union all
select * from table where fname like '% XX%' order by fname
union all
select * from table where fname like '% XX' order by fname

结果将是您的订单和字母,然后应用您的过滤器。