简而言之:在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或仅限几个查询。在我的情况下,每个人发出一个查询将不具有可扩展性或高效性。
答案 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()方法是关键所在。它会将结果自动映射到事件类型的对象。
除非你别无选择,否则我不推荐这种方法。