Группировка по неделям в LINQ to Entities - PullRequest
39 голосов
/ 29 июня 2009

У меня есть приложение, которое позволяет пользователям вводить время, которое они проводят за работой, и я пытаюсь создать для этого хорошую отчетность, которая использует LINQ to Entities. Поскольку каждый TrackedTime имеет TargetDate, который является просто частью "Дата" в DateTime, относительно просто сгруппировать время по пользователю и дате (я опускаю предложения "где" для простоты) :

var userTimes = from t in context.TrackedTimes
                group t by new {t.User.UserName, t.TargetDate} into ut
                select new
                {
                    UserName = ut.Key.UserName,
                    TargetDate = ut.Key.TargetDate,
                    Minutes = ut.Sum(t => t.Minutes)
                };

Благодаря свойству DateTime.Month группировка по пользователю и месяцу лишь немного сложнее:

var userTimes = from t in context.TrackedTimes
                group t by new {t.User.UserName, t.TargetDate.Month} into ut
                select new
                {
                    UserName = ut.Key.UserName,
                    MonthNumber = ut.Key.Month,
                    Minutes = ut.Sum(t => t.Minutes)
                };

Теперь самое сложное. Есть ли надежный способ группировки по неделям? Я попробовал следующее на основе этого ответа на похожий вопрос LINQ to SQL:

DateTime firstDay = GetFirstDayOfFirstWeekOfYear();
var userTimes = from t in context.TrackedTimes
                group t by new {t.User.UserName, WeekNumber = (t.TargetDate - firstDay).Days / 7} into ut
                select new
                {
                    UserName = ut.Key.UserName,
                    WeekNumber = ut.Key.WeekNumber,
                    Minutes = ut.Sum(t => t.Minutes)
                };

Но LINQ to Entities не поддерживает арифметические операции над объектами DateTime, поэтому не знает, как это сделать (t.TargetDate - firstDay).Days / 7.

Я подумал о создании представления в базе данных, которое просто отображает дни в недели, а затем добавляет это представление в мой контекст Entity Framework и присоединяется к нему в моем запросе LINQ, но это похоже на большую работу для чего-то вроде этот. Есть ли хороший обходной путь для арифметического подхода? Что-то, что работает с Linq to Entities, что я могу просто включить в оператор LINQ, не касаясь базы данных? Какой-нибудь способ рассказать Linq Entities, как вычесть одну дату из другой?

Краткое описание

Я хотел бы поблагодарить всех за их вдумчивые и творческие ответы. После всего этого, похоже, реальный ответ на этот вопрос - «подождите до .NET 4.0». Я собираюсь отдать награду Нолдорину за самый практичный ответ, который до сих пор использует LINQ, и особенно упомянуть Джейкоба Проффитта за то, что он придумал ответ, который использует Entity Framework без необходимости изменений на стороне базы данных. Были и другие отличные ответы, и если вы смотрите на вопрос впервые, я настоятельно рекомендую прочитать все те, за которые проголосовали, а также их комментарии. Это действительно был превосходный пример силы StackOverflow. Спасибо всем!

Ответы [ 13 ]

0 голосов
/ 12 июля 2009

лямбда считается? Я начал с синтаксиса linq, но мне кажется, что в лямбда-выражениях C # 3.0 речь идет о декларативном программировании.

public static void TEST()
{
    // creating list of some random dates
    Random rnd = new Random();
    List<DateTime> lstDte = new List<DateTime>();
    while (lstDte.Count < 100)
    {
        lstDte.Add(DateTime.Now.AddDays((int)(Math.Round((rnd.NextDouble() - 0.5) * 100))));
    }
    // grouping 
    var weeksgrouped = lstDte.GroupBy(x => (DateTime.MaxValue - x).Days / 7);
}
0 голосов
/ 01 июля 2009

Ну, это может быть больше работы в зависимости от того, как индексирована БД, но вы можете просто отсортировать по дням, а затем выполнить отображение дня -> недели на стороне клиента.

0 голосов
/ 30 июня 2009

Вы можете попробовать метод расширения для преобразования:

static int WeekNumber( this DateTime dateTime, DateTime firstDay) {
    return (dateTime - firstDay).Days / 7;
}

Тогда у вас будет:

DateTime firstDay = GetFirstDayOfFirstWeekOfYear();
var userTimes = from t in context.TrackedTimes
                group t by new {t.User.UserName, t.TargetDate.WeekNumber( firstDay)} into ut
                select new
                {
                    UserName = ut.Key.UserName,
                    WeekNumber = ut.Key.WeekNumber,
                    Minutes = ut.Sum(t => t.Minutes)
                };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...