NHibernate - 检索父/子,其标准仅适用于儿童

May*_*ayo 5 nhibernate join filter

我有一个父实体,其中包含子实体列表.当使用NHibernate从SQL中检索具有子项的给定父项时,如果没有子项或者如果子项的日期与where条件匹配,则它可以正常工作.

如果存在与where子句不匹配的子项,则父项为null.我希望父项初始化为空子列表.

有关如何修改下面的代码以实现此目的的任何想法?

实体:

public class Parent
{
    public int ParentId;
    public IList<Child> Children { get; set; }

    public Parent()
    {
        Children = new List<Child>();
    }
}

public class Child
{
    public int ChildId;
    public DateTime ChildDate;
    public Parent Parent { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

库:

IList<Parent> foundParents = new List<Parent>();

var criteria1 = DetachedCriteria.For<Parent>()
    .Add(Restrictions.Eq("ParentId", parentId))
    .CreateCriteria("Children", JoinType.LeftOuterJoin)
        .Add(Restrictions.Or(
            Restrictions.IsNull("ChildDate"), // no children at all
            Restrictions.And(
                Restrictions.Ge("ChildDate", startDate),
                Restrictions.Le("ChildDate", endDate)
            )
        ));

foundParents = Session
    .CreateMultiCriteria()
    .Add<Parent>(criteria1)
    .SetResultTransformer(new DistinctRootEntityResultTransformer())
    .List()[0] as List<Parent>;
Run Code Online (Sandbox Code Playgroud)

如果我为此编写SQL,我会将日期比较与左连接而不是在where子句中.我无法弄清楚如何使用NHibernate来做到这一点.

May*_*ayo 5

这需要进行大量研究 - 找到答案的关键是术语过滤器。我通过从 ANSIJoinFragment.cs 中的 AddJoin 开始挖掘 NHibernate 源代码来发现这个术语 - 该代码支持连接的附加条件,所以我认为这是可能的。

无论如何,这是使用过滤器的修订代码(实体类保持不变)。

存储库:

IList<Parent> foundParents = new List<Parent>();

var criteria1 = DetachedCriteria.For<Parent>()
    .Add(Restrictions.Eq("ParentId", parentId))
    .CreateCriteria("Children", JoinType.LeftOuterJoin);

Session.EnableFilter("dateFilter")
    .SetParameter("startDate", startDate)
    .SetParameter("endDate", endDate);

foundParents = Session
    .CreateMultiCriteria()
    .Add<Parent>(criteria1)
    .SetResultTransformer(new DistinctRootEntityResultTransformer())
    .List()[0] as List<Parent>;
Run Code Online (Sandbox Code Playgroud)

我还必须通过添加 filter 和 filter-def 元素来修改我的 Parent 映射。

<class name="Parent" table="Parents">

  ...
  <bag name="Children" table="Children">
    ...
    <filter name="dateFilter" 
      condition="ChildDate BETWEEN :startDate and :endDate" />
  </bag>
</class>

<filter-def name="dateFilter">
  <filter-param name="startDate" type="System.DateTime" />
  <filter-param name="endDate" type="System.DateTime" />
</filter-def>
Run Code Online (Sandbox Code Playgroud)

此外,对遇到此问题且不使用过滤器的任何人的警告。如果您决定在带有 where 子句的原始查询没有产生记录时返回没有填充子项的父实体,则任何命中子项集的代码都将导致 NHibernate 加载整个表。