Un altro problema di pivot LINQ: convertire lo script SQL in LINQ
Domanda
Ci sono alcune domande su SO già riguardanti i pivot LINQ e mentre un paio di essi delineano il mio esatto problema, non riesco a tradurli con successo in una soluzione funzionante. Ritengo che ciò sia dovuto principalmente a un join nei miei tavoli.
Quindi, a beneficio di tutti i drogati di LINQ là fuori che amano un problema, ecco un altro enigma da risolvere. Aiutami (e guadagna alcuni punti reputazione e molto rispetto da me) convertendo il seguente script proc memorizzato SQL in LINQ:
ALTER PROCEDURE [dbo].[GetTimesheetForWeekById]
@timesheetid int,
@begindate VarChar(20),
@enddate VarChar(20)
AS
BEGIN
SELECT T.TaskName,
SUM(
case DATEPART(weekday, TE.StartTime)
WHEN 1 THEN DATEDIFF(minute, TE.StartTime, TE.EndTime) ELSE 0 END
) AS Sunday,
SUM(
case DATEPART(weekday, TE.StartTime)
when 2 THEN DATEDIFF(minute, TE.StartTime, TE.EndTime) ELSE 0 END
) AS Monday,
SUM(
case DATEPART(weekday, TE.StartTime)
when 3 THEN DATEDIFF(minute, TE.StartTime, TE.EndTime) ELSE 0 END
) AS Tuesday,
SUM(
case DATEPART(weekday, TE.StartTime)
when 4 THEN DATEDIFF(minute, TE.StartTime, TE.EndTime) ELSE 0 END
) AS Wednesday,
SUM(
case DATEPART(weekday, TE.StartTime)
when 5 THEN DATEDIFF(minute, TE.StartTime, TE.EndTime) ELSE 0 END
) AS Thursday,
SUM(
case DATEPART(weekday, TE.StartTime)
when 6 THEN DATEDIFF(minute, TE.StartTime, TE.EndTime) ELSE 0 END
) AS Friday,
SUM(
case DATEPART(weekday, TE.StartTime)
when 6 THEN DATEDIFF(minute, TE.StartTime, TE.EndTime) ELSE 0 END
) AS Saturday
FROM Tasks T
INNER JOIN TimeEntries TE on T.TaskID = TE.TaskID
WHERE TE.StartTime BETWEEN
(CONVERT(datetime, @begindate, 103)) AND (CONVERT(datetime, @enddate, 103))
AND TE.TimesheetID = @timesheetid
GROUP BY T.TaskName
END
Soluzione
Bene, supponendo che la chiave esterna abbia una rappresentazione di oggetto, qualcosa come:
int timesheetId = ...
DateTime start = ..., end = ...
var qry = from timeEntry in ctx.TimeEntries
let date = timeEntry.StartTime.Date
where timeEntry.TimesheetId == timesheetId
&& date >= start
&& date <= end
group timeEntry by timeEntry.Task.TaskName into grp
select new {
TaskName = grp.Key,
Monday = grp.Where(x => x.StartTime.DayOfWeek == DayOfWeek.Monday).Count(),
Tuesday = grp.Where(x => x.StartTime.DayOfWeek == DayOfWeek.Tuesday).Count(),
Wednesday = grp.Where(x => x.StartTime.DayOfWeek == DayOfWeek.Wednesday).Count(),
Thursday = grp.Where(x => x.StartTime.DayOfWeek == DayOfWeek.Thursday).Count(),
Friday = grp.Where(x => x.StartTime.DayOfWeek == DayOfWeek.Friday).Count()
};
Sfortunatamente, alcune delle specifiche dipendono dal provider SQL, ovvero quali funzioni (come DayOfWeek ecc.) possono mappare correttamente come TSQL. Fammi sapere se riscontri problemi ...
Altri suggerimenti
Come va (modifica di Marc):
var qry = from timeEntry in timeEntries
let date = timeEntry.StartTime.Date
where timeEntry.TimesheetId == timesheetId
&& date >= start
&& date <= end
group timeEntry by timeEntry.Task.TaskName into grp
select new
{
TaskName = grp.Key,
Monday = grp.Where(x => x.StartTime.DayOfWeek == DayOfWeek.Monday)
.Sum(x=>x.EndTime.Subtract(x.StartTime).TotalMinutes),
Tuesday = grp.Where(x => x.StartTime.DayOfWeek == DayOfWeek.Tuesday)
.Sum(x => x.EndTime.Subtract(x.StartTime).TotalMinutes),
Wednesday = grp.Where(x => x.StartTime.DayOfWeek == DayOfWeek.Wednesday)
.Sum(x => x.EndTime.Subtract(x.StartTime).TotalMinutes),
Thursday = grp.Where(x => x.StartTime.DayOfWeek == DayOfWeek.Thursday)
.Sum(x => x.EndTime.Subtract(x.StartTime).TotalMinutes),
Friday = grp.Where(x => x.StartTime.DayOfWeek == DayOfWeek.Friday)
.Sum(x => x.EndTime.Subtract(x.StartTime).TotalMinutes),
};