Reputation: 5872
I have a table AppointmentStatusHistory
in the following format:
AppointmentId AppointmentStatusId Date
========================================================
1 1 2/1/2012 (2nd January)
1 2 2/2/2012 (2nd February)
I currently run a query against this to return the 'most recent' status for the appointment within a given timeframe.
My LINQ Query
items = (from t1 in db.AppointmentStatusHistories
from t2 in db.TaskAppointments
.Where(o => (o.ID == t1.AppointmentId))
from t3 in db.Tasks
.Where(o => (o.Task_ID == t2.Parent_Task_ID))
where t1.Timestamp >= first && t1.Timestamp <= last
&& t3.Creator == user
group t1 by t1.AppointmentId into grp
select new UserAppointmentTargetModel
{
AppointmentId = grp.Key,
AppointmentStatusId = grp.OrderByDescending(g => g.Timestamp)
.FirstOrDefault()
.AppointmentStatusId
}
);
Using the above returns AppointmentStatusId status of '1' when first=1/1/2012 and last=2/1/2012.
Requirements
I hoped somebody may be able to give me some advice on amending this to meet the following conditions:
Upvotes: 0
Views: 2146
Reputation: 110111
You just need to move the last
part of the filtering to after the grouping/winnerpicking.
db.AppointmentStatusHistories
.Where(ash => first <= ash.TimeStamp) //omit all records that are before the range
.Where(ash => ash.Appointment.TaskAppointments.Any(ta => ta.Task.Creator == user))
.GroupBy(ash => ash.AppointmentId)
.Select(g => g.OrderByDescending(ash => ash.TimeStamp).First()) //pick a winner
.Where(ash => ash.TimeStamp <= last) //omit winners that are after the range
.Select(ash => new UserAppointmentTargetModel()
{
AppointmentId = ash.AppointmentId,
AppoinementStatusId = ash.AppointmentStatus,
Date = ash.Timestamp
}
(obligatory query comprehension syntax form of the above)
from ash in db.AppointmentStatusHistories
where first <= ash.TimeStamp
where ash.Appointment.TaskAppointments.Any(ta => ta.Task.Creator == user)
group ash by ash.AppointmentId into g
let winner = g.OrderByDescending(ash => ash.TimeStamp).First()
where winner.TimeStamp <= last
select new UserAppointmentTargetModel()
{
AppointmentId = winner.AppointmentId,
AppoinementStatusId = winner.AppointmentStatus,
Date = winner.Timestamp
}
Side notes:
I used navigation properties to do the user filtering. If you can't get that to work, go back to the joins.
It's always safe to call First on a Group. Groups aren't ever empty. There's no need for FirstOrDefault in this case.
I reused the ash
variable name in the method style query to communicate type since it is declared in two different places where the type is not stated. I changed that to winner
in the comprehension style query to communicate intent better since it is declared in one place where the type may be verified by inspection.
Also, I never use >= with dates. It can only lead to sorrow.
Upvotes: 4