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

时间:2010-10-25 16:32:01

标签: 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; }
}

存储库:

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

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

1 个答案:

答案 0 :(得分:4)

这需要大量研究 - 找到答案的关键是术语过滤器。我通过在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>;

我还必须通过添加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>

此外,对于遇到此问题但未使用过滤器的任何人,请提出警告。如果您决定在没有填充子项的情况下返回Parent实体,而带有where子句的原始查询不会生成任何记录,则任何命中子集的代码都将导致NHibernate加载整个表。