I'm trying to take the Top(X) recors for every unique item in a column.
Example:
Inspections
InspectionId | RestaurauntName | InspectionDate
------------------------------------------------
1 Mom&Pop 10/10/12
2 SandwichesPlace 10/10/12
3 Mom&Pop 10/10/11
4 SandwichesPlace 10/10/11
5 Mom&Pop 10/10/10
6 SandwichesPlace 10/10/10
7 BurgerPlace 10/10/11
8 BurgerPlace 10/10/09
9 BurgerPlace 10/10/08
If I pass the value of '2' as the parameter I want the records 1, 2, 3, 4, 7, 8 returned.
In this example snippet I'm attempting to take a few records for each 'restaurantName'.
public IQueryable<Inspections>
GetLatestInspectionDatesForAllRestaurants(int numRecords) {
IQueryable<Inspections> inspections= _session.Query<Inspections>()
.GroupBy(r=> r.RestaurauntName)
.SelectMany(g => g
.OrderBy(r => r.InspectionDate)
.Take(numRecords));
return inspections;
}
Unfortunately I'm getting this error.
Query Source could not be identified:
ItemName = g, ItemType = System.Linq.IGrouping`2
The exception triggers at this point in code
var inspections = _inspectionRepository.GetLatestInspectionDatesForAllRestaurants(2).ToList();
What am I missing?
After running a test I have confirmed the query runs fine in LINQ-To-Objects. Is it possible NHibernate.Linq is still incomplete in this area? I did a slightly different query (below) and got a not implemented exception.
.GroupBy(r=> r.RestaurauntName)
.Select(g => g.First()).Take(5)
If I drop the Take(5) from the end I get the following (reminder this is a sample, my PK is Id in my real case).
{"Column '.Id' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause."}
Do I need to learn to use create criteria or something?
Well I got the SQL I needed generated, it took some research and whatnot. I'm convinced my original issue had to do with LINQ and NHibernate, though that last query Robert posted was technically correct as a workaround.
This will generate a single SQL script due to the nature of IQueryable not enumerating until necessary. The SQL itself generates 'Where Exists' clause.
public IQueryable<Inspections>
GetLatestInspectionDatesForAllRestaurants(int numRecords)
{
var subQuery = _session.Query<Inspections>()
.OrderByDescending(x => x.InspectionDate);
var inspections = _session.Query<Inspections>()
.Where(x => subQuery.Where(y => y.InspectionDate ==
x.InspectionDate).Take(numRecords).Contains(x))
.OrderBy(x => x.WellDataId);
return inspections;
}
There it is, hopefully it helps someone else eventually.
public class Inspections{
public int InspectionId {get;set;}
public string RestaurantName {get;set;}
public DateTime InspectionDate {get;set;}
}
void Main()
{
var result=GetLatestInspectionDatesForAllRestaurants(2);
result.Dump();
}
public IQueryable<Inspections>
GetLatestInspectionDatesForAllRestaurants(int numRecords) {
var i = new[]{
new Inspections{InspectionId=1,RestaurantName="Mom&Pop",InspectionDate=DateTime.Parse("10/10/12")},
new Inspections{InspectionId=2,RestaurantName="SandwichesPlace",InspectionDate=DateTime.Parse("10/10/12")},
new Inspections{InspectionId=3,RestaurantName="Mom&Pop",InspectionDate=DateTime.Parse("10/10/11")},
new Inspections{InspectionId=4,RestaurantName="SandwichesPlace",InspectionDate=DateTime.Parse("10/10/11")},
new Inspections{InspectionId=5,RestaurantName="Mom&Pop",InspectionDate=DateTime.Parse("10/10/10")},
new Inspections{InspectionId=6,RestaurantName="SandwichesPlace",InspectionDate=DateTime.Parse("10/10/10")},
new Inspections{InspectionId=7,RestaurantName="BurgerPlace",InspectionDate=DateTime.Parse("10/10/11")},
new Inspections{InspectionId=8,RestaurantName="BurgerPlace",InspectionDate=DateTime.Parse("10/10/09")},
new Inspections{InspectionId=9,RestaurantName="BurgerPlace",InspectionDate=DateTime.Parse("10/10/08")}
};
var result=i.GroupBy(g=>g.RestaurantName).SelectMany(g=>g.OrderByDescending(d=>d.InspectionDate).Take(2));
return result.AsQueryable();
}
This runs just fine, so I am assuming that you are having a problem with the lifetime of your original queryable. Try the following:
public IQueryable<Inspections>
GetLatestInspectionDatesForAllRestaurants(int numRecords)
{
IQueryable<Inspections> inspections= _session.Query<Inspections>()
.GroupBy(r=> r.RestaurauntName)
.SelectMany(g => g
.OrderByDescending(r => r.InspectionDate)
.Take(numRecords));
return inspections.ToList().AsQueryable();
}
Here's a 3rd option, that performs badly, but should eliminate NHibernate from the equation:
public IQueryable<Inspections>
GetLatestInspectionDatesForAllRestaurants(int numRecords)
{
IQueryable<Inspections> inspections= _session.Query<Inspections>().ToList()
.GroupBy(r=> r.RestaurauntName)
.SelectMany(g => g
.OrderByDescending(r => r.InspectionDate)
.Take(numRecords));
return inspections.ToList().AsQueryable();
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.