次のように、特定の文字グループを持つ値を取得するクエリを送信する必要があります。
「XX」に興味があるので、値が「XX」で始まるフィールドまたは「XX」(スペースXX)を持つフィールドを検索する必要があるとします。たとえば、XXCDEF
、PD XXRF
およびCMKJIEK 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();
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を使用することをお勧めします。
HibernateはOrderをサポートしています: http://docs.jboss.org/hibernate/orm/4.2/devguide/en-US/html/ch11.html#ql-ordering 特別な基準のため、 Hibernateで注文をカスタマイズする必要があります。このリンクが役立つ場合があります: http://blog.tremend.ro/2008/06/10/how-to-order-by-a-custom-sql-formulaexpression-when-using-hibernate-criteria-api /
2つの選択を実行します。1つは「XX」で始まるすべての文字列に対してフィルタリングされ、もう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;
}
結果をメモリで並べ替えたくない場合は、条件を変更できます。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
結果はあなたの順序でアルファベット順になり、そしてあなたのフィルターを適用します。
ばかげているが、あなたの場合にはうまくいくかもしれない。
正しい結果が得られたので、次のように結果を再構築できます。
やっとまとめて
リストnewList = new ArrayList(L1);
newList.addAll(L2);
ご注意ください。 Collections.sortは、その要素の自然な順序に従っています。