Criteria API が返す結果セットが小さすぎる
-
24-09-2019 - |
質問
どうしてこんなことが可能なのか、基準に従わなければなりません
Criteria criteria = getSession().createCriteria(c);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.add(Restrictions.eq("active",true));
List list = criteria.list();
リストのサイズは 20 になりました。条件に最大結果を追加すると、
Criteria criteria = getSession().createCriteria(c);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.setMaxResults(90);
criteria.add(Restrictions.eq("active",true));
List list = criteria.list();
..リストのサイズは 18 になりました。
行の量が定義された最大値よりも小さいため、最大結果を定義した後に結果セットのサイズがどのように小さくなるのか理解できません。これは確かにバグのようです、それとも私が気づいていない休止状態の奇妙な側面がまたあるのでしょうか?
この質問に対する答えを探している場合は、承認された回答とそのコメントを必ず読んでください。
解決
は休止状態でデバッグすると生成されたクエリを比較するSQLをオンにすることで、非常にはっきりと見ることができます。
かなり単純Sale
→Item
1対多マッピング(できれば自明である)を使用し、、このようなCriteria
ベースのクエリ
Criteria c = sessionFactory.getCurrentSession().createCriteria(Sale.class);
c.createAlias("items", "i");
c.add(Restrictions.eq("i.name", "doll"));
c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
c.setMaxResults(2);
は、次のようにSQLを生成します:
select top ? this_.saleId as saleId1_1_, ...
from Sale this_
inner join Sale_Item items3_ on this_.saleId=items3_.Sale_saleId
inner join Item items1_ on items3_.items_id=items1_.id
where items1_.name=?
このようなQuery
に対します:
Query q = sessionFactory.getCurrentSession().createQuery("select distinct s from Sale s join s.items as i where i.name=:name");
q.setParameter("name", "doll");
q.setMaxResults(2);
のようなものを生成します:
select top ? distinct hibernated0_.saleId as saleId1_
from Sale hibernated0_
inner join Sale_Item items1_ on hibernated0_.saleId=items1_.Sale_saleId
inner join Item hibernated2_ on items1_.items_id=hibernated2_.id
where hibernated2_.name=?
最初の行(DISTINCT
)の違いに注意してください。 ResultTransformer
のようなDISTINCT_ROOT_ENTITY
はSQLが実行されたの後のSQL列の結果を処理するJavaクラスです。したがって、あなたはSQLに行制限として適用されるmaxResults
を指定した場合、 SQLを使用すると、90 のサブ要素にあなたのSQLの結果を制限しているので、Collection
の要素に参加含んの。 DISTINCT_ROOT_ENTITY
変圧器が適用されると、それは要素が90の接合結果に最初に出てくることが起こるどのルートに純粋に依存し、20未満のルート要素をもたらすことができる。
DISTINCT
キーワード、を使用する点で DISTINCT
HQLで、非常に動作が異なります。したがって、この振る舞いは、あなたが期待するように、と2の違いを説明します。
あなたはSQLレベルでの投影を適用するためにsetProjection
されているはずです - c.setProjection(Projections.distinct(Projections.rootEntity()))
のようなもの - 残念ながらProjections.rootEntity()
は、私はちょうどそれを作った、存在しません。おそらく、それが必要!
他のヒント
はsetMaxResultsは、外での仕事は、SQLクエリに参加していません。多分これはあなたの問題がある: Hibernateは、外でのクエリのための明確な結果を返さないAのために有効に結合フェッチコレクション(私は明確なキーワードを使用している場合でも)にはます。
・ホープ、このことができヘルプ
public List<Employee> getData(int to, int from) {
Criteria hCriteria = null;
List<Employee> viewDataList = null;
List<Employee> exactDataList = null;
try {
hSession = HibernateSessionFactory.getSession();
hTransaction = hSession.beginTransaction();
hCriteria = hSession.createCriteria(Employee.class);
/*
hCriteria.setFirstResult(to);
hCriteria.setFirstResult(from);
*/
hCriteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
viewDataList = hCriteria.list();
// for limit
exactDataList=viewDataList.subList(from,to);
hTransaction.commit();
} catch (Exception e) {
hTransaction.rollback();
} finally {
try {
hSession.flush();
HibernateSessionFactory.closeSession();
} catch (Exception hExp) {
}
}
return exactDataList;
}
別の解決策は次のとおりです。
- あなたの
criteria.list()
エイリアスを設定しない場合 => ルート エンティティの参照セット/リストはプロキシで埋められます => ここで最大結果などを正しく設定します - 同じ休止状態セッションでエイリアス基準を独自に実行 => 上記のプロキシが初期化されます
このようなもの:
Criteria criteria = this.getSession().createCriteria(User.class);
criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);
criteria.setMaxResults(10);
// First get the results without joining with the other tables
List<User> results = criteria.list();
// at this point the set roles is filled with proxies
// we'll now create and execute the join so these proxies are filled since we're still in the same session
getSession().createCriteria(User.class, "u")
.createAlias("u.roles", "r", CriteriaSpecification.LEFT_JOIN)
.list();
return results;
これがお役に立てば幸いです。
ステイン
このは、Hibernateにおける既知の問題です。生成されたSQLと問題の説明については@Cowanを見てください。そのJIRAで、このためのオープンなバグ要求があります。誰かがそれに沿って修正来ることをしてみましょう希望:)