Ich versuche, Paging mithilfe einer zeilenbasierten Begrenzung (zum Beispiel: setFirstResult(5)
und setMaxResults(10)
) für eine Hibernate Criteria-Abfrage zu implementieren , die Verknüpfungen zu anderen Tabellen aufweist.
Verständlicherweise werden Daten zufällig abgeschnitten. und der Grund dafür wird hier erklärt .
Als Lösung wird auf der Seite vorgeschlagen, anstelle eines Joins eine "zweite SQL-Auswahl" zu verwenden.
Wie kann ich meine vorhandene Kriterienabfrage (für die Verknüpfungen verwendet werden createAlias()
) konvertieren, um stattdessen eine verschachtelte Auswahl zu verwenden?
Ich benutze diesen mit meinen Codes.
Fügen Sie dies einfach Ihren Kriterien hinzu:
Dieser Code entspricht der Auswahl, die sich von der Tabelle des nativen SQL unterscheidet. Hoffe das hilft.
quelle
Eine leichte Verbesserung auf der Grundlage von FishBoys Vorschlag.
Es ist möglich, diese Art der Abfrage in einem Treffer und nicht in zwei getrennten Schritten durchzuführen. Das heißt, die einzelne Abfrage unten zeigt unterschiedliche Ergebnisse korrekt an und gibt auch Entitäten anstelle von nur IDs zurück.
Verwenden Sie einfach eine DetachedCriteria mit einer ID-Projektion als Unterabfrage und fügen Sie dann Paging-Werte zum Hauptkriterienobjekt hinzu.
Es wird ungefähr so aussehen:
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();
quelle
Eine kleine Verbesserung des Vorschlags von @ FishBoy ist die Verwendung der ID-Projektion, sodass Sie den Namen der ID-Eigenschaft nicht fest codieren müssen.
quelle
Die Lösung:
funktioniert sehr gut.
quelle
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));
Das hat mir geholfen: D.
quelle
Wenn Sie ORDER BY verwenden möchten, fügen Sie einfach Folgendes hinzu:
criteria.setProjection( Projections.distinct( Projections.projectionList() .add(Projections.id()) .add(Projections.property("the property that you want to ordered by")) ) );
quelle
Ich werde jetzt eine andere Lösung erläutern, bei der Sie die normale Abfrage- und Paginierungsmethode verwenden können, ohne das Problem möglicherweise doppelter oder unterdrückter Elemente zu haben.
Diese Lösung hat den Fortschritt, dass es ist:
Den vollständigen Artikel finden Sie in meinem Blog
Der Ruhezustand bietet die Möglichkeit, die Methode zum Abrufen von Zuordnungen nicht nur zur Entwurfszeit, sondern auch zur Laufzeit durch eine Abfrageausführung zu definieren. Daher verwenden wir diesen Ansatz in Verbindung mit einem einfachen Relfektionsmaterial und können auch den Prozess des Änderns des Abrufalgorithmus für Abfrageeigenschaften nur für Sammlungseigenschaften automatisieren.
Zuerst erstellen wir eine Methode, die alle Sammlungseigenschaften aus der Entitätsklasse auflöst:
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; }
Anschließend können Sie mit dieser kleinen Hilfsmethode Ihrem Kriterienobjekt empfehlen, den FetchMode für diese Abfrage in SELECT zu ändern.
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();
Dies unterscheidet sich von der Definition des FetchMode Ihrer Entitäten zur Entwurfszeit. Sie können also das normale Abrufen von Verknüpfungszuordnungen für Paging-Algorithmen in Ihrer Benutzeroberfläche verwenden, da dies meistens nicht der kritische Teil ist und es wichtiger ist, dass Ihre Ergebnisse so schnell wie möglich vorliegen.
quelle
Im Folgenden sehen Sie, wie Sie eine Mehrfachprojektion durchführen können, um Distinct auszuführen
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(); } }
Beispielnutzung:
String propertyNames = "titleName;titleDescr;titleVersion" criteria countCriteria = .... countCriteria.setProjection(ExtraProjections.countMultipleDistinct(propertyNames);
Referenziert von https://forum.hibernate.org/viewtopic.php?t=964506
quelle
NullPointerException
in manchen Fällen! Ohnecriteria.setProjection(Projections.distinct(Projections.property("id")))
alle Fragen geht es gut! Diese Lösung ist schlecht!Eine andere Möglichkeit ist die Verwendung von SQLQuery. In meinem Fall funktioniert der folgende Code einwandfrei:
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();
Die Unterscheidung erfolgt in der Datenbank! Im Gegensatz zu:
wo die Unterscheidung im Speicher erfolgt, nach dem Laden von Entitäten!
quelle