I have the following domain mapped through FluentNHibernate

class Point
{
    public int Id { get; set; }
    public string Label { get; set; }
}

class PointData
{
    public int Id { get; set; }        
    public DateTime Hour { get; set; } 
    public decimal Value { get; set; }
    public Point Location { get; set; }
    public DateTime Available { get; set; } // Data arrival (data tracking)
}

The PointData table will update frequently inserting new values (updates not supported) for an Hour, but not all points write PointData at the same frequency.

I need to get the latest PointData per Point for all hours between startTime and endTime and before timeOfSnapshot(available).

My query so far using Linq to Nhibernate using group by does not work:

Query.Where(x => x.Available <= available && x.Hour >= startHour && x.Hour < endHour)
                    .OrderByDescending(x => x.Available)
                    .GroupBy(x => new {x.Location, x.Hour})
                    .Select(g => g.First())
                    .ToList();

All searches so far only came up with SQL queries, which is not exactly what I want.

Help is appriciated

有帮助吗?

解决方案

Join the group by result with the original rows and return the rows:

rows.Join(
   rows.GroupBy(x => new {x.Location, x.Hour}), 
   x => new {x.Location, x.Hour, x.Available}, 
   g => new {g.Key.Location, g.Key.Hour, Available = g.Max(p=>p.Available)},
   (x1,g1) => x1
)

Put a profiler on and you will see this sql:

SELECT [t0].*
FROM [rows] AS [t0]
INNER JOIN (
    SELECT MAX([t1].[Available]) AS [value], [t1].[Location], [t1].[Hour]
    FROM [rows] AS [t1]
    GROUP BY [t1].[Location], [t1].[Hour]) 
AS [t2] ON (
    [t0].[Location] = [t2].[Location]) 
    AND ([t0].[Hour] = [t2].[Hour]) 
    AND ([t0].[Available] = [t2].[value]
)

其他提示

After a group by, you cannot extract more columns than are used in the grouping key, or aggregates. If I understand your question correctly, the usual pattern for this is to use a subquery that will pick the identifiers of the interesting rows, then an outer query to get all the columns for those rows. Try something like this:

var latestPointId =
    Query.Where(x => x.Available <= available && x.Hour >= startHour && x.Hour < endHour)
        .OrderByDescending(x => x.Available)
        .GroupBy(x => new {x.Location, x.Hour})
        .Select(g => g.Max(pd => pd.Id));

session.Query<PointData>
    .Where(pd => latestPointId.Contains(pd.Id)
    .ToList();
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top