Вопрос

Я ищу способ получить "окружающие" строки в запросе NHibernate с учетом первичного ключа и порядка сортировки?

Например.У меня есть таблица с записями журнала, и я хочу отобразить запись с первичным ключом 4242 и предыдущие 5 записей, а также следующие 5 записей, упорядоченных по дате (прямой связи между датой и первичным ключом нет).Такой запрос должен возвращать всего 11 строк (при условии, что мы не близки ни к одному из концов).

Таблица записей журнала может быть огромной, и получить все, чтобы разобраться в ней, невозможно.

Существует ли такое понятие, как номер строки, которое можно использовать из NHibernate?Базовой базой данных будет либо SQLite, либо Microsoft SQL Server.

Отредактированный Добавлен образец

Представьте себе такие данные, как следующие:

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

При запросе записи с первичным ключом 4242 мы должны получить строки с 1237, 1238 и 4239 по 4247.Заказ осуществляется по времени, идентификатору.

Возможно ли получить записи в одном запросе (который, очевидно, может включать подзапросы)?Время - это неуникальный столбец, поэтому несколько записей имеют одинаковое значение, и в этом примере невозможно изменить разрешение таким образом, чтобы оно стало уникальным!

Это было полезно?

Решение

"нет прямой связи между датой и первичным ключом" означает, что первичные ключи расположены не в последовательном порядке?

Тогда я бы сделал это вот так:

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

Существует риск наличия нескольких элементов с одинаковым временем.


Редактировать

Теперь это должно сработать.

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

Другие советы

Это должно быть относительно легко с помощью API критериев NHibernate:

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

Здесь ваш listOfIds это просто строго типизированный список целых чисел, представляющих идентификаторы записей, которые вы хотите получить (целые числа с 4242-5 по 4242 + 5 ).

Конечно, вы могли бы также добавить Expressions это позволяет вам извлекать идентификаторы больше 4242-5 и меньше 4242 + 5.

Решение Стефана определенно работает, но существует лучший способ использовать один select и вложенные подзапросы:

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

Это синтаксис NHibernate 2.0, но то же самое справедливо и для более ранних версий, где вместо Ограничений вы используете Expression .

Я протестировал это в тестовом приложении, и оно работает так, как рекламируется

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top