I know this could be a possible duplicate question, pardon me if it is.
Is there a way to GroupBy
all the records from the database by date?
So:
- say i have multiple records for this date 22/05/2022
- and say i have multiple records from this date: 23/05/2022
Can i group all the records based on date parameter 22/05 and 23/05?
So that i would end up with a list containing n
list for each day.
Here is what i did:
var grpQuery = await ctx.Registration.GroupBy(c => c.DateReference.Day).ToListAsync();
Where:
Registration
is my table from where i am pulling the dataDateReference
is aDate
object containing the date
But i am getting this error "the linq expession could not be translated".
Can somone give me some advice on this?
EDIT
I tried this but it seems not to load any data, even setting break a break point will not return anything:
var grpQuery = await query.GroupBy(d => new { DateReference = d.DateReference.Date }).Select(c => new RegistrationViewModel()
{
RegistrationId = c.FirstOrDefault().RegistrationId,
PeopleId = c.FirstOrDefault().PeopleId,
DateReference = c.Key.DateReference,
DateChange = c.FirstOrDefault().DateChange,
UserRef = c.FirstOrDefault().UserRef,
CommissionId = c.FirstOrDefault().CommissionId,
ActivityId = c.FirstOrDefault().ActivityId,
MinuteWorked = c.FirstOrDefault().MinuteWorked,
}).OrderBy(d => d.DateReference).ToListAsync();
Where:
RegistrationViewModel
contains all those properties includingDateReference
- If i call the method using the API is stuck at "pending"
CodePudding user response:
First, don't. Even if the query was fixed, the equivalent query in the database would be GROUP BY DATEPART(day,registration.Date) which can't use indexes and therefore is slow.
According to the docs the equivalent of DATEPART(day, @dateTime)
is dateTime.Day
. The query still needs to have a proper Select
though.
A correct query would be :
counts = ctx.Registrations.GroupBy(r=>r.RegistrationDate.Day)
.Select(g=>new {Day=g.Key,Count=g.Count())
.ToList();
The equivalent, slow query would be
SELECT DATEPART(day,registration.Date) as Day,count(*)
FROM Registrations
GROUP BY DATEPART(day,registration.Date)
Things get worse if we have to eg filter by date. The query would have to scan the entire table because it wouldn't be able to use any indexes covering the Date
column
SELECT DATEPART(day,registration.Date) as Day,count(*)
FROM Registrations
WHERE Date >'20220901'
GROUP BY DATEPART(day,registration.Date)
Imagine having to scan 10 years of registrations only to get the current month.
This is a reporting query. For date related reports, using a prepopulated Calendar table can make the query infinitely easier.
SELECT Calendar.Day,COUNT(*)
FROM Registrations r
INNER JOIN Calendar on r.RegistrationDate=Calendar.Date
GROUP BY Calendar.Day
or
SELECT Calendar.Year, Calendar.Semester, Calendar.Day,COUNT(*)
FROM Registrations r
INNER JOIN Calendar on r.RegistrationDate=Calendar.Date
WHERE Calendar.Year = @someYear
GROUP BY Calendar.Year, Calendar.Semester,Calendar.Day
A Calendar table or Date dimension is a table with prepopulated dates, years, months, semesters or any other reporting period along with their names or anything needed to make reporting easier. Such a table can contain eg 10 or 20 years of data without taking a lot of space. To speed up queries, the columns can be aggressively indexed without taking too much extra space.
Doing the same in EF Core requires mapping Calendar
as an entity and performing the JOIN in LINQ. This is one of the cases where it makes no sense to add a relation between entities :
var query=from registration in ctx.Registrations
join date in Calendar
on registration.Date equals Calendar.Date
group registration by date.Day into g
select new { Day=g.Key, Count=g.Count()};
var counts = query.ToList();
CodePudding user response:
If you are using EF Core Please try this:
var grpQuery = await ctx.Registration.GroupBy(c => SqlServerDbFunctionsExtensions.DateDiffDay(c.DateReference,DateTime.Today)).ToListAsync();