我使用嵌套集模型存储类别的层次结构,也就是说,每个类别都有一个Left
和一个Right
值,每个类别都有一个比任何父项更高Left
和更小的值。Right
我想查询属于某个类别(包括该类别)的子类别的所有类别。也就是说,我需要从给定类别开始的整个子树。
如果子树的根 id 由 @catId 给出,我可以使用以下 SQL 来获取子树:
select *
from Category c,
(select [Left], [Right] from Category where Id = @catId) as t
where c.[Left] >= t.[Left]
and c.[Right] <= t.[Right]
现在我正在尝试使用 NHibernate 和 QueryOver API 来做类似的事情。那是我有点卡住的地方。
如果我把它分成两个查询,这很容易:
var cat = session.Get<Category>(catId);
var matches = session.QueryOver<Category>()
.Where(x => x.Left >= cat.Left && x.Right <= cat.Right)
.List();
但这是两个查询 - 一个会更好。我试图提出一个使用子查询的解决方案,虽然这在技术上可行,但查询可能不是最佳的,因为现在执行了两个子查询而不是一个。
var matches = session.QueryOver<Category>()
.WithSubquery.WhereProperty(x => x.Left)
.Ge(QueryOver.Of<Category>()
.Where(c => c.Id == catId)
.Select(c => c.Left))
.WithSubquery.WhereProperty(x => x.Right)
.Le(QueryOver.Of<Category>()
.Where(c => c.Id == catId)
.Select(c => c.Right)).List();
(除此之外,并非所有 DBMS 都支持返回标量值的子查询,例如 SqlServerCE,但这是另一个问题)
有没有更好的方法来实现这一目标?如有必要,我可以针对这种情况切换查询 API。因此,如果 eq 在 HQL 中有一种巧妙的方法,我可以接受。