Как использовать NHibernate для извлечения элементов с критериями в списке - PullRequest
5 голосов
/ 28 июня 2010

Я использую NHibernate, и у меня есть два следующих класса, которые отображают мою схему базы данных:

public class A
{
    public virtual int Id { get; set;}
    public virtual List<B> MyList { get; set; }
}

public class B
{
    public virtual int Id { get; set; }
    public virtual DateTime Date { get; set; }
    public virtual A FKtoA { get; set; }
}

Я хотел бы получить все записи таблицы A, которые имеют все элементы своего свойства MyList, с датой меньше заданного значения.

Как я могу сделать это с элегантным синтаксисом NHibernate?

Ответы [ 4 ]

1 голос
/ 29 июня 2010

Я должен вам "элегантную" часть ...: -)

Это возможный HQL.Обратите внимание, что ваше условие перевернулось: вместо поиска "A, у которого все элементы их свойства MyList имеют дату меньше заданного значения" , я ищу "A, которого не имеетлюбые элементов их свойства MyList с датой , превышающей или равной заданному значению ".

from A a
where a not in 
      (select a1
       from A a1, B b
       where b.Date >= :date
       and   b in elements(a1.MyList))

Использование:

var results = session.CreateQuery("hql from above")
                     .SetParameter("date", DateTime.Today)
                     .List();

Обратите внимание, чтоЕсли вы объявите двунаправленное отношение между A и B (добавив свойство A), запрос будет намного проще:

from A a
where a not in 
      (select b.A
       from B b
       where b.Date >= :date)

Обновление: вот как это сделать с помощью критериев:

session.CreateCriteria<A>().Add(
    Subqueries.PropertyNotIn("id",
                             DetachedCriteria.For<A>()
                                 .CreateCriteria("MyList")
                                 .SetProjection(Projections.Property("id"))
                                 .Add(Restrictions.Ge("Date", DateTime.Today))))
0 голосов
/ 20 июля 2011

В настоящее время принятый ответ основан на коррелированном подзапросе, который, как правило, является просто «плохим SQL».

Гораздо лучше просто выразить это, используя семантику на основе множеств, а не более функциональный подход.

По сути, вы хотите, чтобы ваш SQL выглядел так:

SELECT
 A.Id
FROM A
 LEFT OUTER JOIN B ON A.Id = B.FKtoA
WHERE B.Date < @MyDate

Это читается как «Я хочу, чтобы набор столбцов из A относился к набору B, где дата B меньше некоторого значения». Этого можно достичь с помощью API-интерфейса ICriteria:

ICriteria criteria =  session.CreateCriteria<A>();
criteria.CreateAlias("MyList", "b", JoinType.LeftOuterJoin)
criteria.Add(Restrictions.Lt("b.Date", myDate));
criteria.SetResultTransformer(new DistinctRootEntityResultTransformer());
criteria.List<A>();

Частью хитрости является использование встроенного в NHibernate DistinctRootEntityResultTransformer: поскольку левое внешнее объединение может возвращать несколько экземпляров A на B, мы хотим, чтобы наши критерии ICriteria возвращали только отдельные экземпляры (при условии, что нас не волнует порядок или что-то еще еще).

0 голосов
/ 29 июня 2010

если ваш класс B выглядит примерно так (где свойство MyList для A ищет этот FK)

public class B
{
    public virtual int Id { get; set; }
    public virtual DateTime Date { get; set; }
    public virtual A FK_ToA { get; set; }
}

, тогда я думаю, что вы ищете (HQL)

nhSes.CreateQuery("select b.FK_ToA from B b where b.Date < :passedDate")
     .SetTimestamp("passedDate", DateTime.Now).List<A>()
0 голосов
/ 28 июня 2010

Используйте это

ICriteria criteria =  session.CreateCriteria<ClassOfTableOne>();
criteria.CreateAlias("FieldNameOfTypeTable2","aliasName");
criteria.SetFetchMode("aliasName", FetchMode.Join);
criteria.Add(Restrictions.Lt("aliasName.Date", yourdate));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...