NHibernate的 - 检索父/子只适用于儿童的标准 [英] NHibernate - Retrieve parent / children with criteria applied only to children

查看:99
本文介绍了NHibernate的 - 检索父/子只适用于儿童的标准的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



有些子句与where子句不匹配,父类为空。我想让父项初始化为一个空的子列表。



有关如何修改下面的代码来实现这一点的任何想法?
$ b

实体

  public class Parent 
{
public int ParentId;
公共IList< Child>孩子{get;组; }
$ b $ public Parent()
{
Children = new List< Child>();
}
}

public class Child
{
public int ChildId;
public DateTime ChildDate;
公共父母{get;组; }

code

$ b

存储库

  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),//根本没有孩子
Restrictions.And(
Restrictions.Ge(ChildDate ,startDate),
Restrictions.Le(ChildDate,endDate)

));
$ b $ foundParents = Session
.CreateMultiCriteria()
.Add< Parent>(criteria1)
.SetResultTransformer(new DistinctRootEntityResultTransformer())
.List )[0]作为列表< Parent>;

如果我正在为此编写SQL,则会将日期比较与左连接进行比较在where子句中。我不知道如何使用NHibernate做到这一点。

解决方案

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



无论如何...这里是使用过滤器的修改过的代码(实体类保持不变)。
$ b

存储库

  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);
$ b $ foundParents = Session
.CreateMultiCriteria()
.Add< Parent>(criteria1)
.SetResultTransformer(new DistinctRootEntityResultTransformer())
.List )[0]作为列表< Parent>;

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

 < class name =Parenttable =Parents> 

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

< filter-def name =dateFilter>
< filter-param name =startDatetype =System.DateTime/>
< filter-param name =endDatetype =System.DateTime/>
< / tiler-def>

另外,任何遇到这个问题并且不使用过滤器的人都会警告一个字。如果你决定返回没有填充子元素的父实体,当用where子句产生的原始查询不会产生任何记录时,任何碰到子元素集合的代码都会导致NHibernate加载整个表。


I have a parent entity with a list of child entities. When using NHibernate to retrieve a given parent with children from SQL, it works fine if there are no children OR if there are children with dates that match the where condition.

If there are children that do not match the where clause, the parent is null. I want to have the parent initialized with an empty list of children.

Any thoughts on how I can modify the code below to make this happen?

Entities:

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

Repository:

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

If I were writing SQL for this, I would put the date comparison in with the left join and not in the where clause. I can't figure out how to do this with NHibernate.

解决方案

This took alot of research - the key to finding an answer is the term filter. I came across the term by digging through the NHibernate source code starting with AddJoin in ANSIJoinFragment.cs - the code supported additional conditions on the join so I figured it was possible.

Anyway... here's the revised code that utilizes filter (entity class remains the same).

Repository:

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

I also had to modify my mapping for Parent by adding filter and filter-def elements.

<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" />
</tiler-def>

Also, one word of warning for anyone that runs into this problem and doesn't use filters. If you decide to return the Parent entity without the populated children when the original query with the where clause yields no records, any code that hits the set of children will cause NHibernate to load the entire table.

这篇关于NHibernate的 - 检索父/子只适用于儿童的标准的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆