كيفية الحصول على نتائج مميزة في وضع السبات باستخدام الصلات وتحديد الصفوف (الترحيل)؟

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

سؤال

أحاول تنفيذ الترحيل باستخدام التحديد المستند إلى الصف (على سبيل المثال: setFirstResult(5) و setMaxResults(10)) في استعلام معايير السبات الذي يرتبط بجداول أخرى.

ومن المفهوم أن يتم قطع البيانات بشكل عشوائي؛ويتم توضيح سبب ذلك هنا.

كحل، تقترح الصفحة استخدام "تحديد SQL ثانٍ" بدلاً من الانضمام.

كيف يمكنني تحويل استعلام المعايير الحالي الخاص بي (الذي يحتوي على صلات باستخدام createAlias()) لاستخدام تحديد متداخل بدلاً من ذلك؟

هل كانت مفيدة؟

المحلول

يمكنك تحقيق النتيجة المرجوة عن طريق طلب قائمة بالمعرفات المميزة بدلاً من قائمة الكائنات المائية المميزة.

ما عليك سوى إضافة هذا إلى معاييرك:

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

ستحصل الآن على العدد الصحيح من النتائج وفقًا للقيود المستندة إلى الصف.سبب نجاح ذلك هو أن جهاز الإسقاط سيقوم بالتحقق من التمييز كجزء من استعلام SQL، بدلاً من ما يفعله ResultTransformer وهو تصفية النتائج للتميز بعد تم تنفيذ استعلام SQL.

تجدر الإشارة إلى أنه بدلاً من الحصول على قائمة بالكائنات، ستحصل الآن على قائمة بالمعرفات، والتي يمكنك استخدامها لترطيب الكائنات من السبات لاحقًا.

نصائح أخرى

وأنا أستخدم هذا واحد مع رموز بلدي.

وببساطة هذا إضافة إلى المعايير الخاصة بك:

<اقتباس فقرة>   

وcriteria.setResultTransformer (Criteria.DISTINCT_ROOT_ENTITY)؛

وسوف هذا الرمز يكون مثل اختيار متميز * من جدول SQL الأصلي. نأمل أن يكون هذا واحد يساعد.

ومبنى تحسن طفيف على اقتراح FishBoy ل.

ومن الممكن للقيام بهذا النوع من الاستعلام في ضربة واحدة، وليس على مرحلتين منفصلتين. أي في استعلام واحد أدناه الصفحة إرادة نتائج مميزة بشكل صحيح، وأيضا العودة الكيانات بدلا من مجرد معرفات.

وببساطة استخدام DetachedCriteria مع إسقاط معرف على أنه فرعي، ثم قم بإضافة القيم الترحيل على كائن المعايير الرئيسية.

ووسوف ننظر بشيء من هذا القبيل:

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 هو استخدام إسقاط الهوية، لذلك لم يكن لديك إلى رمز القرص الثابت اسم الخاصية معرف.

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 المذكور في هذه المقالة
  • يحافظ على الترتيب ولا يستخدم عبارة "in" في مجموعة بيانات كبيرة محتملة من PK

يمكن العثور على المادة كاملة على مدونتي

يوفر السبات إمكانية تحديد طريقة جلب الارتباط ليس فقط في وقت التصميم ولكن أيضًا في وقت التشغيل من خلال تنفيذ الاستعلام.لذلك نستخدم هذا النهج جنبًا إلى جنب مع عناصر تفكير بسيطة ويمكننا أيضًا أتمتة عملية تغيير خوارزمية جلب خاصية الاستعلام لخصائص المجموعة فقط.

نقوم أولاً بإنشاء طريقة تحل جميع خصائص المجموعة من فئة الكيان:

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 إلى SELECT في هذا الاستعلام.

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 لكياناتك في وقت التصميم.لذلك يمكنك استخدام جلب اقتران الانضمام العادي على خوارزميات الترحيل في واجهة المستخدم الخاصة بك، لأن هذا في معظم الأحيان ليس الجزء الحاسم ومن الأهم أن تحصل على نتائجك في أسرع وقت ممكن.

وفيما يلي الطريقة يمكننا القيام به الإسقاط متعددة لأداء متميز

    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("id"))) كل الاستعلام على ما يرام! هذا الحل هو سيء!

وهناك طريقة أخرى هي استخدام 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