在NHibernate查询中获取“周围”行

时间:2009-05-08 08:56:26

标签: sql-server nhibernate sqlite hql

我正在寻找一种在给定主键和排序顺序的NHibernate查询中检索“周围”行的方法吗?

E.g。我有一个包含日志条目的表,我想显示带有主键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.顺序是按时间,Id。

是否可以在单个查询中检索条目(显然可以包含子查询)?时间是一个非唯一列,因此多个条目具有相同的值,在此示例中,无法以使其唯一的方式更改分辨率!

3 个答案:

答案 0 :(得分:1)

“日期和主键之间没有直接关系”意味着主键不是按顺序排列的?

然后我会这样做:

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

答案 1 :(得分:0)

使用NHibernate的Criteria API,这应该相对容易:

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

这里你的listOfIds只是一个强类型的整数列表,表示你想要检索的条目的id(整数4242-5到4242 + 5)。

当然,您还可以添加Expressions,以便检索大于4242-5且小于4242 + 5的ID。

答案 2 :(得分:0)

Stefan的解决方案确实有效,但使用单个选择和嵌套的子查询存在更好的方法:

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的限制。

我已经在测试应用程序上对此进行了测试,它的工作方式与广告一致