Domanda

Sto cercando un modo per recuperare il "circostante". righe in una query NHibernate con una chiave primaria e un ordinamento?

es. Ho una tabella con voci di registro e voglio visualizzare la voce con la chiave primaria 4242 e le precedenti 5 voci nonché le seguenti 5 voci ordinate per data (non esiste una relazione diretta tra data e chiave primaria). Tale query dovrebbe restituire 11 righe in totale (purché non siamo vicini a nessuna delle due estremità).

La tabella delle voci di registro può essere enorme e non è possibile recuperare tutto per capirlo.

Esiste un concetto come il numero di riga che può essere utilizzato da NHibernate? Il database sottostante sarà SQlite o Microsoft SQL Server.

Modificato Esempio aggiunto

Immagina dati come i seguenti:

Id   Time
4237 10:00
4238 10:00
1236 10:01
1237 10:01
1238 10:02
4239 10:03
4240 10:04
4241 10:04
4242 10:04   <-- requested "center" row
4243 10:04
4244 10:05
4245 10:06
4246 10:07
4247 10:08

Quando richiediamo la voce con la chiave primaria 4242 dovremmo ottenere le righe da 1237, 1238 e 4239 a 4247. L'ordine è in base a Time, Id.

È possibile recuperare le voci in una singola query (che ovviamente può includere sottoquery)? Time è una colonna non univoca, quindi diverse voci hanno lo stesso valore e in questo esempio non è possibile modificare la risoluzione in modo da renderla unica!

È stato utile?

Soluzione

"non esiste una relazione diretta tra data e chiave primaria" significa che le chiavi primarie non sono in un ordine sequenziale?

Quindi lo farei così:

Item middleItem = Session.Get(id);

IList<Item> previousFiveItems = Session.CreateCriteria((typeof(Item))
  .Add(Expression.Le("Time", middleItem.Time))
  .AddOrder(Order.Desc("Time"))
  .SetMaxResults(5);

IList<Item> nextFiveItems = Session.CreateCriteria((typeof(Item))
  .Add(Expression.Gt("Time", middleItem.Time))
  .AddOrder(Order.Asc("Time"))
  .SetMaxResults(5);

Esiste il rischio di avere più articoli contemporaneamente.


Modifica

Ora dovrebbe funzionare.

Item middleItem = Session.Get(id);

IList<Item> previousFiveItems = Session.CreateCriteria((typeof(Item))
  .Add(Expression.Le("Time", middleItem.Time)) // less or equal
  .Add(Expression.Not(Expression.IdEq(middleItem.id))) // but not the middle
  .AddOrder(Order.Desc("Time"))
  .SetMaxResults(5);

IList<Item> nextFiveItems = Session.CreateCriteria((typeof(Item))
  .Add(Expression.Gt("Time", middleItem.Time))  // greater 
  .AddOrder(Order.Asc("Time"))
  .SetMaxResults(5);

Altri suggerimenti

Questo dovrebbe essere relativamente semplice con l'API dei criteri di NHibernate:

List<LogEntry> logEntries = session.CreateCriteria(typeof(LogEntry))
.Add(Expression.InG<int>(Projections.Property("Id"), listOfIds))
.AddOrder(Order.Desc("EntryDate"))
.List<LogEntry>();

Qui il tuo listOfIds è solo un elenco fortemente tipizzato di numeri interi che rappresentano gli ID delle voci che desideri recuperare (numeri interi da 4242-5 a 4242 + 5).

Naturalmente puoi anche aggiungere espressioni che ti consentono di recuperare ID maggiori di 4242-5 e inferiori a 4242 + 5.

La soluzione di Stefan funziona sicuramente, ma esiste un modo migliore utilizzando una singola subquery selezionata e nidificata:

ICriteria crit = NHibernateSession.CreateCriteria(typeof(Item));

        DetachedCriteria dcMiddleTime =
            DetachedCriteria.For(typeof(Item)).SetProjection(Property.ForName("Time"))
            .Add(Restrictions.Eq("Id", id));

        DetachedCriteria dcAfterTime =
            DetachedCriteria.For(typeof(Item)).SetMaxResults(5).SetProjection(Property.ForName("Id"))
            .Add(Subqueries.PropertyGt("Time", dcMiddleTime));
        DetachedCriteria dcBeforeTime =
            DetachedCriteria.For(typeof(Item)).SetMaxResults(5).SetProjection(Property.ForName("Id"))
                .Add(Subqueries.PropertyLt("Time", dcMiddleTime));

        crit.AddOrder(Order.Asc("Time"));
        crit.Add(Restrictions.Eq("Id", id) || Subqueries.PropertyIn("Id", dcAfterTime) ||
                 Subqueries.PropertyIn("Id", dcBeforeTime));

        return crit.List<Item>();

Questa è la sintassi di NHibernate 2.0 ma lo stesso vale per le versioni precedenti in cui invece di Restrizioni si usa Expression.

L'ho testato su un'applicazione di test e funziona come pubblicizzato

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top