группировка по объединению и агрегированию (linq) - PullRequest
0 голосов
/ 28 сентября 2011

У меня проблема с запросом LINQ, и я не знаю, как ее решить: /

У меня есть два стола. Один - с атрибутами, а второй - строки из атрибутов, но мне нужно суммировать часы по строкам и получить их по атрибутам; не могу объяснить это очень хорошо;) Вот мой запрос, который я пытался создать:

var query = (from ta in session.db.TimesheetAttributes
             join tr in session.db.TimesheetRows on ta.Id equals tr.TimesheetAttributesId into tempTR
             from ttr in tempTR.DefaultIfEmpty()
             group ttr by new { ta.TimesheetId, ta.Date, ta.SickNote, ta.Vacation, ta.OccasionVacation } into g
             select new
             {
                 Id = g.Key.TimesheetId,
                 Date = g.Key.Date,
                 WeekDay = g.Key.Date.ToString("dddd", new CultureInfo("pl-PL")),
                 Description = String.Format("{0:dd/MM/yyyy}", g.Key.Date),
                 SickNote = g.Key.SickNote,
                 Vacation = g.Key.Vacation,
                 OccasionVacation = g.Key.OccasionVacation,
                 Hours = String.Format("{0:HH:mm}", (new DateTime(g.Aggregate(TimeSpan.Zero, (subtotal, t) => subtotal + (t.DateTo - t.DateFrom)).Ticks)))
             }).OrderBy(c=>c.Date).ToList();

Проблема в том, что не у каждого атрибута есть строки, поэтому я попытался использовать DefaultIfEmpty (), однако этот запрос не работает: (

Мой старый запрос работает, но мой ORM создает новый запрос для каждой строки, поэтому, если у меня есть 1000 атрибутов Timesheet, он делает 1000 выборок: /

Вот мой старый запрос:

var query = (from c in session.db.TimesheetAttributes
             where ((c.Active == true)
                    && (c.Timesheet.Active == true)
                    && (c.ValidFrom <= validDate)
                    && (c.ValidTo > validDate)
                    && (c.Timesheet.ContactPersonId == session.ContactPersonAttributes.ContactPersonId))
             select new
             {
                 Id = c.TimesheetId,
                 c.Date,
                 WeekDay = c.Date.ToString("dddd", new CultureInfo("pl-PL")),
                 Description = String.Format("{0:dd/MM/yyyy}", c.Date),
                 Hours = String.Format("{0:HH:mm}", (new DateTime((c.TimesheetRows.Aggregate(TimeSpan.Zero, (subtotal, t) => subtotal + (t.DateTo - t.DateFrom)).Ticks)))),
                 c.SickNote,
                 c.Vacation,
                 c.OccasionVacation
              }).OrderBy(c => c.Date).ToList();

EDIT:

Это то, что я получаю как исключение: «Исключение было сгенерировано целью вызова» InnerException: «Ссылка на объект не установлена ​​для экземпляра объекта»

1 Ответ

0 голосов
/ 28 сентября 2011

Проблема с вашим старым запросом часто называется n + 1 проблемой .

Вы должны иметь возможность адаптировать исходный запрос следующим образом:

var query = (from c in session.db.TimesheetAttributes 
             from cr in c.TimesheetRows
             where ((c.Active == true) 
                    && (c.Timesheet.Active == true) 
                    && (c.ValidFrom <= validDate) 
                    && (c.ValidTo > validDate) 
                    && (c.Timesheet.ContactPersonId == session.ContactPersonAttributes.ContactPersonId)) 
             select new 
             { 
                 Id = c.TimesheetId, 
                 c.Date, 
                 WeekDay = c.Date.ToString("dddd", new CultureInfo("pl-PL")), 
                 Description = String.Format("{0:dd/MM/yyyy}", c.Date), 
                 Hours = String.Format("{0:HH:mm}", (new DateTime((cr.Aggregate(TimeSpan.Zero, (subtotal, t) => subtotal + (t.DateTo - t.DateFrom)).Ticks)))), 
                 c.SickNote, 
                 c.Vacation, 
                 c.OccasionVacation 
              }).OrderBy(c => c.Date).ToList(); 

Если это все еще гудит, вы можете попробовать добавить тенарный оператор в свойство Hours ...

Hours = String.Format("{0:HH:mm}", !(cr == null) && cr.Any() ? (new DateTime((cr.Aggregate(TimeSpan.Zero, (subtotal, t) => subtotal + (t.DateTo - t.DateFrom)).Ticks))) : DateTime.MinValue

EDIT:

Теперь я понимаю, что вы имеете в виду, мой мозг еще не совсем проснулся. Проблема, с которой вы столкнулись, заключается в том, что основной поставщик запросов не замечает, что ему нужно извлечь TimesheetAttributes И связанные / связанные TimesheetRows. Вероятно, это связано с тем, что TimesheetRows глубоко скрыты в выражении, которое генерирует выбранные вами анонимные типы.

Синтаксис моего запроса не блестящий (я предпочитаю делать это в лямбде - я чувствую, что это больше будущее , но это всего лишь ощущение), но я попробую ...

var query = (from res in 
                 (from c in session.db.TimesheetAttributes           
                 where ((c.Active == true)           
                        && (c.Timesheet.Active == true)           
                        && (c.ValidFrom <= validDate)           
                        && (c.ValidTo > validDate)           
                        && (c.Timesheet.ContactPersonId == session.ContactPersonAttributes.ContactPersonId))           
                 select new           
                 {   
                     c = c,
                     cr = c.TimesheetRows
                 })
             select new
             {
                 Id = c.TimesheetId,           
                 c.Date,           
                 WeekDay = c.Date.ToString("dddd", new CultureInfo("pl-PL")),           
                 Description = String.Format("{0:dd/MM/yyyy}", c.Date),           
                 Hours = String.Format("{0:HH:mm}", (new DateTime((cr.Aggregate(TimeSpan.Zero, (subtotal, t) => subtotal + (t.DateTo - t.DateFrom)).Ticks)))),           
                 c.SickNote,           
                 c.Vacation,           
                 c.OccasionVacation           
              }).OrderBy(c => c.Date).ToList();  

Это выглядит уродливее, чем оригинал, и я уверен, что есть лучший способ сделать это, но оно должно сделать выражение достаточно ясным для вашего поставщика запросов (L2S или что-то еще), чтобы понять, что ему нужно вернуть обе сущности, и избежать проблемы n + 1.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...