NHibernate - 从聚合中选择完整记录

时间:2011-11-16 15:58:13

标签: .net nhibernate aggregate-functions

简而言之:在NHibernate中给定一个聚合查询(一个包含Max,Min,Count等),如何修改查询以返回与聚合值相关的完整记录? / p>

我的示例:我有两个表:People(主键:PersonId)与Events的关系为1对多(主键:EventId;其他列:PersonId,EventDate)。

我想选择每个人的最后一个事件并生成这些事件的列表。每个人最后一个事件的SQL类似于SELECT PersonId, Max(EventDate) FROM ... GROUP BY PersonId。到目前为止,NHibernate查询看起来像:

ICriteria criteria = session.CreateCriteria<Event>()
    .SetProjection(Projections.ProjectionList()
        .Add(Projections.GroupProperty("PersonId"))
        .Add(Projections.Max("EventDate"))
    );

现在我真正需要的是完整的活动信息。理论上,一种解决方案是基本上将上述标准通过PersonId和最大EventDate加入Events表(在纯SQL中很容易)。但是我不知道如何在NHibernate中执行此操作。

我对任何建议(HQL,LINQ等)持开放态度,只要它避免存储过程和视图,并且仅限于1或仅限几个查询。在我的情况下,每个人发出一个查询将不具有可扩展性或高效性。

2 个答案:

答案 0 :(得分:3)

我希望您也对QueryOver开放(可以将其转换为ICriteria)......

Event eventAlias = null;

var topEventsByPerson = Session.QueryOver<Event>(() => eventAlias)
    .WithSubquery.WhereProperty(x => x.EventId).Eq(QueryOver.Of<Event>()
        .Where(x => x.Person == eventAlias.Person)
        .OrderBy(x => x.EventDate).Desc
        .Select(x => x.EventId)
        .Take(1))
    .List();

答案 1 :(得分:1)

虽然我更喜欢dotjoe的答案,但由于在使用QueryOver别名时抛出了ArgumentNullException,因此我无法实现它。我怀疑这是NHibernate 3.1中的一个错误。

相反,我找到了一个使用 ISession.CreateSQLQuery()的解决方案,我用纯SQL编写查询:

var results = session.CreateSQLQuery(@"
        SELECT Events.*
        FROM Events
        join (
                SELECT MAX(EventDate) as MaxEventDate, PersonId
                FROM Events
                GROUP BY PersonId
            )
            as q_LastEventsPerPerson
            on  (Events.EventDate = q_LastEventsPerPerson.MaxEventDate)
            and (Events.PersonId = q_LastEventsPerPerson.PersonId)
    ")
    .AddEntity(typeof(Event))
    .List<Event>();

AddEntity()方法是关键所在。它会将结果自动映射到事件类型的对象。

除非你别无选择,否则我不推荐这种方法。