Получить “окружающие” строки в запросе NHibernate
-
22-07-2019 - |
Вопрос
Я ищу способ получить "окружающие" строки в запросе 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 .
Я протестировал это в тестовом приложении, и оно работает так, как рекламируется