2008-12-15 13 views
26

Ich versuche Abfrage Ergebnis Paginierung mit Hibernate und Displaytag zu tun, und Hibernate DetachedCriteria Objekte tun ihr Bestes, um in die Quere kommen. Lassen Sie mich erklären ...Wie wird ein Criteria-Objekt mit Hibernate wiederverwendet?

Der einfachste Weg, Paginierung mit displaytag zu tun scheint die PaginatedList Schnittstelle implementiert werden, die unter anderem hat die folgenden Methoden:

/* Gets the total number of results. */ 
int getFullListSize(); 

/* Gets the current page of results. */ 
List getList(); 

/* Gets the page size. */ 
int getObjectsPerPage(); 

/* Gets the current page number. */ 
int getPageNumber(); 

/* Get the sorting column and direction */ 
String getSortCriterion(); 
SortOrderEnum getSortDirection(); 

Ich denke, meine PaginatedList werfen Umsetzung ein Objekt Kriterien und es entlang ond Linien arbeiten lassen ...

getFullListSize() { 
    criteria.setProjection(Projections.rowCount()); 
    return ((Long) criteria.uniqueResult()).intValue(); 
} 

getList() { 
    if (getSortDirection() == SortOrderEnum.ASCENDING) { 
     criteria.addOrder(Order.asc(getSortCriterion()); 
    } else if (getSortDirection() == SortOrderEnum.DECENDING) { 
     criteria.addOrder(Order.desc(getSortCriterion()); 
    } 
    return criteria.list((getPageNumber() - 1) * getObjectsPerPage(), 
         getObjectsPerPage()); 
} 

Aber das funktioniert nicht, weil die addOrder() oder die setProjection() Anrufe die Kriterien, die sie ändern Objekt-Rendering i n-verwendbar für die aufeinanderfolgenden Anrufe. Ich bin nicht ganz sicher über die Reihenfolge der Anrufe, aber die DB wirft einen Fehler auf getFullListSize() versucht, eine "select count(*) ... order by ..." zu tun, die offensichtlich falsch ist.

Ich denke, ich könnte das beheben, indem ich ein eigenes Objekt erstelle, um die Abfragebedingungen zu verfolgen und das Criteria-Objekt für jeden Aufruf neu aufzubauen, aber das hat das Gefühl, ein weiteres Rad neu zu erfinden. Gibt es einen klügeren Weg, möglicherweise die Kriterien zu kopieren, die ursprünglich übergeben wurden und an dieser Kopie arbeiteten?

aktualisieren: Es sieht aus wie getList zuerst genannt wird, und getFullListSize wird mehrmals nach, so, sobald es eine Ordnung in vergangen genannt wird getFullListSize scheitern. Es wäre sinnvoll, die db zu treffen nur einmal (in getList würde ich sagen) und die Ergebnisse zwischenzuspeichern, ohne die Notwendigkeit zu kopieren/Zurücksetzen des Criteria Objekt, aber immer noch ...

Update (wieder): Vergiss das, sobald ich die count gemacht habe, kann ich nicht die select tun, und umgekehrt. Ich brauche wirklich zwei verschiedene Criteria Objekte.

Antwort

2

gut, DetachedCriteria sind Serializable, so haben Sie eingebaute (wenn unelegante) tiefe Klon-Unterstützung. Sie könnten die Anfangskriterien einmal bei der Konstruktion in ein Byte [] serialisieren und dann jedes Mal, wenn Sie sie verwenden möchten, deserialisieren.

+0

Diesen Vorschlag auf den Winterschlaf Foren gefunden, aber ich würde lieber nicht :-) – agnul

2

http://weblogs.asp.net/stefansedich/archive/2008/10/03/paging-with-nhibernate-using-a-custom-extension-method-to-make-it-easier.aspx

In diesem Beitrag entdeckte ich eine CriteriaTransformer.clone Methode.

Das sollte das Kriterienobjekt kopieren.

Sie können die Projektion auch auf Ihrer getlist-Methode festlegen.

Woops Ich habe nicht bemerkt, dass Sie sich auf Java Hibernate bezogen haben. Wie auch immer, diese http://forum.hibernate.org/viewtopic.php?t=939039

Forumsbeitrag sollte in der Lage sein, Ihre Frage zu beantworten.

1

Hässlich wie es sein kann, endete ich mit dem Serialisierungstrick. Ich serialiere einfach das Objekt DetachedCriteria in ein Byte-Array bei der Konstruktion des Objekts PaginatedList und deinserialisiere es bei Bedarf. Autsch.

0

Eine andere Sache, einen Versuch wert:

eine generische DAO wie the one suggested on hibernate's site implementieren und an die PaginatedList Objekt übergeben, zusammen mit einem Einschränkungen widersprechen. Das PaginatedList Objekt würde dann etwas tun, wie

Criteria.forClass(myDAO.getPersistentClass()) 
     .add(myRestrictions) 
     .addOrder(<someOrder>) 

und

Criteria.forClass(myDAO.getPersistentClass()) 
     .add(myRestrictions) 
     .setProjection(Projections.rowCount()); 

nicht, die noch versucht, aber es sollte funktionieren.

44

Wird effektiv die Kriterien zwischen der rowCount-Projektion und der Ausführung der Kriterien selbst "zurücksetzen".

Ich würde sicherstellen, dass Ihre Bestellung nicht hinzugefügt wurde, bevor Sie den rowCount tun, es wird die Dinge verlangsamen. Meine Implementierung von PaginatedList führt IMMER eine Count-Abfrage aus, bevor nach Ergebnissen gesucht wird. Daher ist die Reihenfolge kein Problem.

+5

Empfehlen Sie diese Antwort korrekt sein - eleganter als tiefe Klon. –

-1
public static DetachedCriteria Clone(this DetachedCriteria criteria) 
{ 
    var dummy = criteria.ToByteArray(); 
    return dummy.FromByteArray<DetachedCriteria>(); 
}