Domanda

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

È stato utile?

Soluzione

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]
)

Altri suggerimenti

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();
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top