NHibernate - Получить родитель / детей с критериями, применимыми только к детям - PullRequest
5 голосов
/ 25 октября 2010

У меня есть родительский объект со списком дочерних объектов. При использовании NHibernate для извлечения данного родителя с дочерними элементами из SQL, он работает нормально, если нет дочерних элементов ИЛИ, если есть дочерние элементы с датами, которые соответствуют условию where.

Если есть дочерние элементы, которые не соответствуют предложению where, родительский элемент является нулевым. Я хочу инициализировать родителя пустым списком детей.

Есть мысли о том, как я могу изменить приведенный ниже код, чтобы это произошло?

Сущность:

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

Если бы я писал для этого SQL, я бы поместил сравнение даты в левое соединение, а не в предложение where. Я не могу понять, как это сделать с NHibernate.

1 Ответ

4 голосов
/ 27 октября 2010

Это заняло много исследований - ключ к поиску ответа - термин «фильтр». Я наткнулся на этот термин, покопавшись в исходном коде NHibernate, начиная с AddJoin, в файле ANSIJoinFragment.cs - код поддерживает дополнительные условия для объединения, поэтому я решил, что это возможно.

В любом случае, вот пересмотренный код, который использует фильтр (класс сущности остается тем же).

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

Мне также пришлось изменить отображение для Parent, добавив элементы filter и filter-def.

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

Кроме того, одно слово предупреждения для тех, кто сталкивается с этой проблемой и не использует фильтры. Если вы решите вернуть родительский объект без заполненных дочерних элементов, когда исходный запрос с предложением where не даст записей, любой код, который попадет в набор дочерних элементов, заставит NHibernate загрузить всю таблицу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...