Hinzufügen eine Projektion auf ein NHibernate Kriterien stoppt sie von der Durchführung Standardelementauswahl

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

Frage

Ich schreibe ein NHibernate Kriterien, die Daten zur Unterstützung Paging auswählt. Ich verwende den Ausdruck COUNT(*) OVER() von SQL Server 2005 (+) hält, die Gesamtzahl der verfügbaren Zeilen zu erhalten, wie vorgeschlagen von Ayende Rahien. Ich brauche diese Zahl in der Lage sein zu berechnen, wie viele Seiten es insgesamt sind. Die Schönheit dieser Lösung ist, dass ich keine zweite Abfrage ausführen muß halten, die Zeilenanzahl zu erhalten.

Allerdings kann ich nicht zu verwalten scheinen eine Arbeits Kriterien schreiben (Ayende nur liefert eine HQL-Abfrage).

Hier ist eine SQL-Abfrage, die zeigt, was ich will und es funktioniert gut. Beachten Sie, dass ich absichtlich weggelassen, die tatsächliche Paging-Logik auf das Problem zu konzentrieren:

SELECT Items.*, COUNT(*) OVER() AS rowcount
FROM Items

Hier ist die HQL:

select
    item, rowcount()
from 
    Item item

Beachten Sie, dass die rowcount() Funktion in einem benutzerdefinierten NHibernate Dialekt registriert und löst in SQL COUNT(*) OVER().

Eine Voraussetzung ist, dass die Abfrage ein Kriterium zum Ausdruck verwendet. Leider weiß ich nicht, wie es richtig zu machen:

var query = Session
    .CreateCriteria<Item>("item")
    .SetProjection(
       Projections.SqlFunction("rowcount", NHibernateUtil.Int32));

Jedes Mal, wenn ich einen Vorsprung hinzufügen, NHibernate wählen nicht item (wie wäre es ohne Projektion), nur die rowcount() während ich wirklich brauchen beides. Auch ich kann nicht scheinen, item als Ganzes zu projizieren, nur es Eigenschaften ist, und ich möchte wirklich nicht alle aufzuzählen.

Ich hoffe, dass jemand eine Lösung für dieses hat. Trotzdem danke.

War es hilfreich?

Lösung

Ich denke, es ist in Kriterien nicht möglich ist, es gewisse Grenzen hat.

Sie können die ID und Teile der Ladung in einer nachfolgenden Abfrage erhalten:

var query = Session
    .CreateCriteria<Item>("item")
    .SetProjection(Projections.ProjectionList()
       .Add(Projections.SqlFunction("rowcount", NHibernateUtil.Int32))
       .Add(Projections.Id()));

Wenn Sie es nicht mögen, verwenden HQL, können Sie die maximale Anzahl der Ergebnisse einstellen können es auch:

IList<Item> result = Session
    .CreateQuery("select item, rowcount() from item where ..." )
    .SetMaxResult(100)
    .List<Item>();

Andere Tipps

Mit CreateMultiCriteria.

Sie können mit nur einem Schlag auf die DB auf diese Weise zwei einfache Anweisungen ausführen.

Ich frage mich, warum Kriterien eine Voraussetzung ist. Können Sie nicht session.CreateSQLQuery verwenden? Wenn Sie es wirklich in einer Abfrage tun müssen, hätte ich vorgeschlagen, die Item-Objekte zurückziehen und die Zählung, wie:

select {item.*}, count(*) over() 
from Item {item}

... diese Weise können Sie zurück Artikel Objekte aus der Abfrage erhalten können, zusammen mit dem Grafen. Wenn Sie ein Problem mit Hibernate Caching auftreten, können Sie auch die Abfrageräume (Einheit / table Caches) konfigurieren mit einer nativen Abfrage zugeordnet, so dass veraltete Abfrage-Cache-Einträge werden automatisch gelöscht werden.

Wenn ich Ihre Frage richtig zu verstehen, muss ich eine Lösung. Ich kämpfte ziemlich viel mit dem gleichen Problem.

Lassen Sie mich das Problem schnell beschreibe ich hatte, um sicherzustellen, dass wir auf der gleichen Seite sind. Mein Problem kam zu Paging nach unten. Ich möchte 10 Datensätze in der Benutzeroberfläche angezeigt werden, aber ich möchte auch die total Anzahl der Datensätze wissen, die den Filterkriterien entsprechen. Ich wollte dies mit dem NH Kriterien API erreichen, aber wenn eine Projektion für Zeilenanzahl hinzufügen, meine Frage nicht mehr gearbeitet, und ich würde keine Ergebnisse nicht bekommen (ich erinnere mich nicht den spezifischen Fehler, aber es klingt wie das, was Sie ist immer).

Hier ist meine Lösung (kopieren und von meinem aktuellen Produktionscode einfügen). Beachten Sie, dass „session“ ist der Name der Geschäftseinheit I für die ausgelagerten Daten bin abrufen, nach 3 Filterkriterium. IsDev, IsRead und IsResolved

ICriteria crit = CurrentSession.CreateCriteria(typeof (SessionError))
    .Add(Restrictions.Eq("WebApp", this));

if (isDev.HasValue)
    crit.Add(Restrictions.Eq("IsDev", isDev.Value));

if (isRead.HasValue)
    crit.Add(Restrictions.Eq("IsRead", isRead.Value));

if (isResolved.HasValue)
    crit.Add(Restrictions.Eq("IsResolved", isResolved.Value));

// Order by most recent
crit.AddOrder(Order.Desc("DateCreated"));

// Copy the ICriteria query to get a row count as well
ICriteria critCount = CriteriaTransformer.Clone(crit)
    .SetProjection(Projections.RowCountInt64());
critCount.Orders.Clear();

// NOW add the paging vars to the original query
crit = crit
    .SetMaxResults(pageSize)
    .SetFirstResult(pageNum_oneBased * pageSize);

// Set up a multi criteria to get your data in a single trip to the database
IMultiCriteria multCrit = CurrentSession.CreateMultiCriteria()
    .Add(crit)
    .Add(critCount);

// Get the results
IList results = multCrit.List();

List<SessionError> sessionErrors = new List<SessionError>();
foreach (SessionError sessErr in ((IList)results[0]))
    sessionErrors.Add(sessErr);

numResults = (long)((IList)results[1])[0];

Also ich meine Basiskriterien erstellen, mit optionalen Einschränkungen. Dann CLONE ich es, und eine Zeilenanzahl Projektion auf die CLONED Kriterien hinzuzufügen. Beachten Sie, dass ich es klonen, bevor Ich fügen Sie die Paging-Einschränkungen. Dann habe ich eine IMultiCriteria bis zu den ursprünglichen und geklonten ICriteria Objekte enthalten, und die IMultiCriteria verwenden beide auszuführen. Jetzt habe ich meine ausgelagerten Daten aus der ursprünglichen ICriteria (und ich schleppte nur die Daten, die ich über den Draht benötigen), und auch eine rohe zählen, wie viele Istsätze angepasst meine Kriterien (nützlich für die Anzeige oder Paging-Links erstellen, oder was auch immer). Diese Strategie hat gut für mich gearbeitet. Ich hoffe, dass dies hilfreich ist.

Ich würde vorschlagen, individuelles Ergebnis Transformator Untersuchung von SetResultTransformer () auf der Sitzung aufgerufen wird.

Erstellen Sie eine Formel-Eigenschaft in der Klasse Mapping:

<property name="TotalRecords" formula="count(*) over()" type="Int32" not-null="true"/>;

IList<...> result = criteria.SetFirstResult(skip).SetMaxResults(take).List<...>();
totalRecords = (result != null && result.Count > 0) ? result[0].TotalRecords : 0;
return result;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top