NHibernate - Select full records from aggregates

三世轮回 提交于 2019-12-10 22:57:23

问题


In short: Given an aggregate query (one with Max, Min, Count, etc) in NHibernate, how can you modify the query to also return the full record associated with the aggregated value?

My example: I have 2 tables: People (primary key: PersonId) with a 1-to-many relationship to Events (primary key: EventId; other columns: PersonId, EventDate).

I want to select the last event per person and generate a list of these events. The SQL for last event per person would be something like SELECT PersonId, Max(EventDate) FROM ... GROUP BY PersonId. So far the NHibernate query looks like:

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

Now what I really need is the full event info. One solution, in theory, is to essentially join the above criteria to the Events table by PersonId and the max EventDate (easy enough in plain SQL). However I'm at a loss of how to perform this in NHibernate.

I'm open to any suggestion (HQL, LINQ, etc.) so long as it avoids stored procedures and views and is limited to 1 or just a few queries. Issuing a query per Person will not be scalable or performant in my case.


回答1:


I hope you are also open to QueryOver (this can be converted to 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();



回答2:


Although I prefer dotjoe's answer I wasn't able to implement it because of an ArgumentNullException thrown when using a QueryOver alias. I suspect this is a bug in NHibernate 3.1.

Instead I found a solution using ISession.CreateSQLQuery() where I write the query in plain 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>();

The AddEntity() method is key here. It causes the automatic mapping of the results to objects of type Event.

I do not recommend this approach unless you have no alternative.



来源:https://stackoverflow.com/questions/8154632/nhibernate-select-full-records-from-aggregates

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!