Dynamically grouping by Day/Week/Month/Year at Runtime

天涯浪子 提交于 2019-12-23 02:28:25

问题


I'd like to group my query differently based on an int passed into my function. Currently I have this very hacky solution:

`.GroupBy(occurrence => new { date = 
                // Bucket by day.
                timeBucket == 0 ? DbFunctions.TruncateTime(occurrence.occurrenceDate) : 
                // Bucket by week.
                timeBucket == 1 ? DbFunctions.AddDays(DbFunctions.CreateDateTime(occurrence.occurrenceDate.Year, 1, 1, 0, 0, 0), 7*(occurrence.occurrenceDate.DayOfYear/7)) : 
                // Bucket by month.
                timeBucket == 2 ? DbFunctions.TruncateTime(DbFunctions.CreateDateTime(occurrence.occurrenceDate.Year, occurrence.occurrenceDate.Month, 1, 1, 1, 1)) :
                // Bucket by year.
                DbFunctions.TruncateTime(DbFunctions.CreateDateTime(occurrence.occurrenceDate.Year, 1, 1, 1, 1, 1)),
                type = occurrence.type })`

The specifics of how I calculate the dates isn't too important to me (but feel free to give help anyway). I would like to avoid having to go through this case statement for each row in the database. Is there anyway to avoid doing this? I've tried a variety of solutions like using an expression, but I couldn't return the object I wanted because the expression tree must be parameterless...

If anyone has a solution it would be much appreciated.

Thanks!


回答1:


Define a grouper class:

class TimeGrouper
{
    public int Year { get; set; }
    public int Month { get; set; }
    public int Week { get; set; }
    public int Day { get; set; }
}

And a function to return an expression:

using System.Data.Entity.SqlServer;
...
Expression<Func<Occurrence, TimeGrouper>> GetGrouper(int grouping)
{
    switch (grouping)
    {
        case 1:
            return o => new TimeGrouper
                        { 
                            Year = o.occurrenceDate.Year
                        };
        case 2:
            return o => new TimeGrouper 
                        { 
                            Year = o.occurrenceDate.Year,
                            Month = o.occurrenceDate.Month
                        };
        case 3:
            return o => new TimeGrouper 
                        {
                            Year = o.occurrenceDate.Year,
                            Week = SqlFunctions.DatePart("wk", o.StartDate).Value
                        };
        default:
            return o => new TimeGrouper
                        {
                            Year = o.occurrenceDate.Year,
                            Day = SqlFunctions.DatePart("dy", o.StartDate).Value
                        };
    }
}

Now you can call

db.Occurrences.GroupBy(GetGrouper(3));



回答2:


Why not just do something like this (mostly pseudo code):

switch(timeBucket)
{
   case 0: result=query.GroupBy(...);
   case 1: result=query.GroupBy(...);
   case 2: result=query.GroupBy(...);
}



回答3:


Grouping by Date, Month, Year is easy. Week varies depending on your calendar week.

            List<DateTime> occurance = new List<DateTime>();

            var dayGroup = occurance.GroupBy(x => x.Date);
            var yearGroup = occurance.GroupBy(x => x.Year);
            var monthGroup = occurance.GroupBy(x => newKeyValuePair<int,int>(x.Month, x.Year));​


来源:https://stackoverflow.com/questions/31082791/dynamically-grouping-by-day-week-month-year-at-runtime

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!