どのように異なる結果にhibernateとの結合に、列に基づく制限(ページング)?

StackOverflow https://stackoverflow.com/questions/300491

質問

ようにしているページングの実施を行型限定(たとえば: setFirstResult(5)setMaxResults(10))はHibernateのクライテリアとして参加その他のテーブル

夜のデータがカットオランダム;およびその理由を説明し こちらの.

ソリューションとして、ページが示唆を"第二のsql select"です。

どのように交換することはできま私の既存のクライテリア(参加を createAlias() 使用入れ子を選択しょうか?

役に立ちましたか?

解決

個別のハイドレートオブジェクトのリストではなく、個別のIDのリストを要求することで、目的の結果を得ることができます。

単純にこれを条件に追加します:

criteria.setProjection(Projections.distinct(Projections.property("id")));

これで、行ベースの制限に従って正しい数の結果が得られます。これが機能する理由は、ResultTransformerが行う処理(後に SQLクエリが実行されました。

注目すべきは、オブジェクトのリストを取得する代わりに、idのリストを取得することです。これを使用して、後で休止状態からオブジェクトをハイドレートできます。

他のヒント

コードでこれを使用しています。

単純にこれを条件に追加します:

  

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

そのコードは、ネイティブSQLのテーブルからselect distinct *のようになります。これがお役に立てば幸いです。

FishBoyの提案に基づいたわずかな改善。

この種のクエリは、2つの別個の段階ではなく、1回のヒットで実行できます。つまり、以下の単一のクエリは個別の結果を正しくページングし、IDだけでなくエンティティも返します。

サブクエリとしてidプロジェクションでDetachedCriteriaを使用し、メインCriteriaオブジェクトにページング値を追加します。

次のようになります:

DetachedCriteria idsOnlyCriteria = DetachedCriteria.forClass(MyClass.class);
//add other joins and query params here
idsOnlyCriteria.setProjection(Projections.distinct(Projections.id()));

Criteria criteria = getSession().createCriteria(myClass);
criteria.add(Subqueries.propertyIn("id", idsOnlyCriteria));
criteria.setFirstResult(0).setMaxResults(50);
return criteria.list();

@FishBoyの提案に対する小さな改善は、idプロジェクションを使用することです。そのため、識別子プロパティ名をハードコーディングする必要はありません。

criteria.setProjection(Projections.distinct(Projections.id()));
session = (Session) getEntityManager().getDelegate();
Criteria criteria = session.createCriteria(ComputedProdDaily.class);
ProjectionList projList = Projections.projectionList();
projList.add(Projections.property("user.id"), "userid");
projList.add(Projections.property("loanState"), "state");
criteria.setProjection(Projections.distinct(projList));
criteria.add(Restrictions.isNotNull("this.loanState"));
criteria.setResultTransformer(Transformers.aliasToBean(UserStateTransformer.class));

これは私を助けました:D

解決策:

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

非常にうまく機能します。

ORDER BYを使用する場合は、追加するだけです:

criteria.setProjection(
    Projections.distinct(
        Projections.projectionList()
        .add(Projections.id())
        .add(Projections.property("the property that you want to ordered by"))
    )
);

ついて、ご説明しま異なる溶液を利用できる通常のクエリやページング手法を持たない問題の複製または抑制されます。

このソリューションの前には:

  • のPK idの解決このページで取り上げた
  • 保存の秩序やかに利用する項"のそれよりも大きなデータセットのPKの

の記事が 私のブログ

Hibernateの可能性を定義する本会の取得のいずれか一方のみで設計時間の短縮も実行時によるクエリを実行します。もしこの形を併せて簡単なrelfectionものでも自動化の過程で変化するクエリの物件取得のアルゴリズムにのみ収集す。

まず最初に作成方法を解決すべての収性のエンティティクラス:

public static List<String> resolveCollectionProperties(Class<?> type) {
  List<String> ret = new ArrayList<String>();
  try {
   BeanInfo beanInfo = Introspector.getBeanInfo(type);
   for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
     if (Collection.class.isAssignableFrom(pd.getPropertyType()))
     ret.add(pd.getName());
   }
  } catch (IntrospectionException e) {
    e.printStackTrace();
  }
  return ret;
}

したいと利用できるこのヘルパーの方法なお条件オブジェクトを変更FetchModeを選択したモードです。

Criteria criteria = …

//    … add your expression here  …

// set fetchmode for every Collection Property to SELECT
for (String property : ReflectUtil.resolveCollectionProperties(YourEntity.class)) {
  criteria.setFetchMode(property, org.hibernate.FetchMode.SELECT);
}
criteria.setFirstResult(firstResult);
criteria.setMaxResults(maxResults);
criteria.list();

やっているかを定義するFetchModeの主体です。用することができ、通常の入会を取得するページングアルゴリズムにおUI、これはあくまでもほとんどの時間の重要な一部であまで以上に重要になってきてい結果とが可能です。

以下は、複数の投影を実行してDistinctを実行する方法です

    package org.hibernate.criterion;

import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.type.Type;

/**
* A count for style :  count (distinct (a || b || c))
*/
public class MultipleCountProjection extends AggregateProjection {

   private boolean distinct;

   protected MultipleCountProjection(String prop) {
      super("count", prop);
   }

   public String toString() {
      if(distinct) {
         return "distinct " + super.toString();
      } else {
         return super.toString();
      }
   }

   public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) 
   throws HibernateException {
      return new Type[] { Hibernate.INTEGER };
   }

   public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery) 
   throws HibernateException {
      StringBuffer buf = new StringBuffer();
      buf.append("count(");
      if (distinct) buf.append("distinct ");
        String[] properties = propertyName.split(";");
        for (int i = 0; i < properties.length; i++) {
           buf.append( criteriaQuery.getColumn(criteria, properties[i]) );
             if(i != properties.length - 1) 
                buf.append(" || ");
        }
        buf.append(") as y");
        buf.append(position);
        buf.append('_');
        return buf.toString();
   }

   public MultipleCountProjection setDistinct() {
      distinct = true;
      return this;
   }

}

ExtraProjections.java

package org.hibernate.criterion; 

public final class ExtraProjections
{ 
    public static MultipleCountProjection countMultipleDistinct(String propertyNames) {
        return new MultipleCountProjection(propertyNames).setDistinct();
    }
}

使用例:

String propertyNames = "titleName;titleDescr;titleVersion"

criteria countCriteria = ....

countCriteria.setProjection(ExtraProjections.countMultipleDistinct(propertyNames);

https://forum.hibernate.org/viewtopic.php?t=から参照964506

場合によっては

NullPointerException criteria.setProjection(Projections.distinct(Projections.property(&quot; id&quot;)))なし すべてのクエリがうまくいきます! この解決策は悪い!

別の方法は、SQLQueryを使用することです。私の場合、次のコードは問題なく動作します:

List result = getSession().createSQLQuery(
"SELECT distinct u.id as usrId, b.currentBillingAccountType as oldUser_type,"
+ " r.accountTypeWhenRegister as newUser_type, count(r.accountTypeWhenRegister) as numOfRegUsers"
+ " FROM recommendations r, users u, billing_accounts b WHERE "
+ " r.user_fk = u.id and"
+ " b.user_fk = u.id and"
+ " r.activated = true and"
+ " r.audit_CD > :monthAgo and"
+ " r.bonusExceeded is null and"
+ " group by u.id, r.accountTypeWhenRegister")
.addScalar("usrId", Hibernate.LONG)
.addScalar("oldUser_type", Hibernate.INTEGER)
.addScalar("newUser_type", Hibernate.INTEGER)
.addScalar("numOfRegUsers", Hibernate.BIG_INTEGER)
.setParameter("monthAgo", monthAgo)
.setMaxResults(20)
.list();

区別はデータベースで行われます!反対の場合:

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

エンティティをロードした後、メモリ内で区別が行われる場所

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top