Pregunta

Estoy buscando una manera de recuperar el " circundante " filas en una consulta NHibernate dada una clave primaria y un orden de clasificación?

Por ejemplo. Tengo una tabla con entradas de registro y quiero mostrar la entrada con la clave principal 4242 y las 5 entradas anteriores, así como las siguientes 5 entradas ordenadas por fecha (no existe una relación directa entre la fecha y la clave principal). Dicha consulta debería devolver 11 filas en total (siempre que no estemos cerca de ninguno de los extremos).

La tabla de entrada de registro puede ser enorme y no es posible recuperar todo para resolverlo.

¿Existe un concepto como el número de fila que se puede usar desde NHibernate? La base de datos subyacente será SQlite o Microsoft SQL Server.

Editado Muestra agregada

Imagine datos como los siguientes:

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

Al solicitar la entrada con la clave primaria 4242, deberíamos obtener las filas 1237, 1238 y 4239 a 4247. El orden es por Tiempo, Id.

¿Es posible recuperar las entradas en una sola consulta (que obviamente puede incluir subconsultas)? ¡El tiempo es una columna no única, por lo que varias entradas tienen el mismo valor y en este ejemplo no es posible cambiar la resolución de una manera que la haga única!

¿Fue útil?

Solución

" no existe una relación directa entre la fecha y la clave primaria " significa que las claves principales no están en orden secuencial?

Entonces lo haría así:

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);

Existe el riesgo de tener varios artículos al mismo tiempo.


Editar

Esto debería funcionar ahora.

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);

Otros consejos

Esto debería ser relativamente fácil con la API de Criterios de NHibernate:

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

Aquí su listOfIds es solo una lista de números enteros fuertemente tipados que representan los identificadores de las entradas que desea recuperar (números enteros 4242-5 a 4242 + 5).

Por supuesto, también puede agregar Expresiones que le permiten recuperar Ids mayores que 4242-5 y menores que 4242 + 5.

La solución de Stefan definitivamente funciona, pero existe una mejor manera usando una sola selección y subconsultas anidadas:

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>();

Esta es la sintaxis de NHibernate 2.0, pero lo mismo es cierto para las versiones anteriores donde, en lugar de las Restricciones, usa Expresión.

He probado esto en una aplicación de prueba y funciona como se anuncia

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top