C# NHibernate 根聚合筛选子集合与子查询

本文关键字:子集合 查询 筛选 NHibernate | 更新日期: 2023-09-27 18:33:18

我正在尝试检索根元素及其子集合的列表,在子集合中应用子查询过滤器。此子查询需要引入 root 的子元素的最后一个匹配项。

预期结果是一个根元素列表,其中每个根元素在子集合属性上仅具有其子元素的最后一次出现。

这些元素的类表示形式:

public class Root {
   public virtual long id { get; set; }
   public virtual ISet<Child> childList { get; set; }
}
public class Child {
   public virtual long id { get; set; }
   public virtual DateTime occurrence { get; set; }
   public virtual Root parent { get; set; }
}

我尝试使用NHibernate的QueryOver创建一个查询,不幸的是它没有按预期工作。

这是我尝试过的代码:

Root rootAlias = null;
Child childAlias = null;
var query = QueryOver.Of(() => rootAlias)
   .Left.JoinAlias(
      () => rootAlias.childList, 
      () => childAlias, 
      Restrictions.Where<Child>(
         cd => cd.occurrence == QueryOver.Of<Child>()
            .Where(cx => cx.parent.id == rootAlias.id)
            .Select(cx => cx.occurrence)
            .OrderBy(cx => cx.occurrence).Desc
            .Take(1)
            .As<DateTime>()
   )                    
);

如果你们能帮助我解决这个问题,甚至为我指出另一种达到上述结果的方法,我会很高兴。

C# NHibernate 根聚合筛选子集合与子查询

在搜索和阅读了数百篇类似的帖子后,我找到了解决我的问题的方法。

正如我在问题中所说:"预期结果是一个根元素列表,其中每个根元素在子集合属性上只有其子元素的最后一次出现。

考虑到我的类结构,这是解决方案:

// Aliases
Root rootAlias = null;
Child x_temp = null;
Child childAlias = null;
// Result list.
IList<Root> roots = null;
// Subquery which retrieves a list of child's id by max occurrence and grouping by 
// root id.
var subquery = CurrentSession.QueryOver<Child>(() => x_temp)
    .SelectList(list => list
        .Select(() => x_temp.id)
        .SelectMax(() => x_temp.occurrence)
        .SelectGroup(() => x_temp.root.id)
    )
    .List<object[]>()
        .Select(p => p[0]).ToArray();
// Query root elements, joining with child collection, applying
// a restriction on child's id attribute through 
// JoinAlias' "With clause" parameter.
var query = QueryOver.Of(() => rootAlias).Left.JoinAlias(
    () => rootAlias.childList,
    () => childAlias,
    Restrictions.On(() => childAlias.id).IsIn(subquery)
);
// retrieves the final result list through the query.
roots = query.GetExecutableQueryOver(CurrentSession).List();

就是这样!

我希望它对有类似问题的其他人有用。