I am trying to return some report data based on a user input frequency (daily, monthly, yearly). My LINQ is the following:
var dataQuery = DataAccess.AppEventRepository.AllNoTracking;
// get property func based on provided filter
Func<AppEvent, DateTime?> timeGroupProp = null;
if (filters.TimeSpanId == (int)TimeSpanEnum.Daily) timeGroupProp = e => e.InsertDay;
if (filters.TimeSpanId == (int) TimeSpanEnum.Monthly) timeGroupProp = e => e.InsertMonth;
if (filters.TimeSpanId == (int) TimeSpanEnum.Yearly) timeGroupProp = e => e.InsertYear;
var groupedDataQuery = dataQuery
// downgrading to LINQ2Object, because Invoke is not supported in LINQ2SQL
.ToList()
.GroupBy(e => new {InsertGroupProp = timeGroupProp?.Invoke(e), e.CountryId})
.Select(grp => new AuditReportGroupingDataModel
{
GroupTime = grp.Key.InsertGroupProp.Value,
CountryId = grp.Key.CountryId.Value,
Count = grp.Count()
});
This works correctly, but the problem is that grouping is done after all data is retrieved from the SQL. The number of events may grow to hundred of thousands in the future and I expect performance degradation.
Question: is it possible to write my query so that I am grouping on the server-side level? (full use of LINQ2SQL, not downgrading to LINQ2Object)
I managed to find two ways of doing this, but not something so small as
Invoke
trial.0) Some POCOs I am using to store the data
1) The ugly way - using conditional operator in GroupBy
My small number of possibilities allow ternary operator usage. However, this does not work properly for an increased number of options.
This works, but generates an ugly and not so efficient SQL statement:
2) Better way - GroupBy expression based on value
This generates better SQL: