2017-02-06 6 views
1

Я создаю приложение отслеживания безопасности отслеживания, и я пытаюсь использовать LINQ для возврата потерянных часов за каждый месяц за тип инцидента с безопасностью. Соответствующие столбцы сущность/таблицы являются:LINQ join, group by, sum

[safety_incident]: 
    [incident_id] 
    [incident_date] 
    [incident_type] 
    [facility_id] 

[safety_hours]: 
    [safety_hours_id] 
    [incident_id] 
    [safety_hours_date] 
    [lost_hours] 

Отношения между safety_incident и safety_hours является 0..n с safety_hours отметить часы утерянные за инцидент на конкретные даты. Я пытаюсь вернуть запись/объект для каждой комбинации типа инцидента и месяца, в течение года (не обязательно все в том же календарном году), где потерянные часы больше 0. Без годичных границ или лимитов на объекте, я получаю то, что мне нужно от SQL с этим:

SELECT (datepart(year,safety_hours_date) * 100 + datepart(month,safety_hours_date)), 
    inc.incident_type, sum(sh.lost_hours) 
FROM [hr].[safety_hours] sh 
INNER JOIN [hr].safety_incident inc ON sh.incident_id = inc.incident_id 
GROUP BY (datepart(year,safety_hours_date) * 100 + datepart(month,safety_hours_date)), 
    inc.incident_type 
HAVING sum(sh.lost_hours) > 0 
ORDER BY (datepart(year,safety_hours_date) * 100 + datepart(month,safety_hours_date)), 
    inc.incident_type 

ближайший я могу добраться до принятого запроса LINQ заключается в следующем:

var monthInjuryHours = 
       from sh in _context.safety_hours 
       where sh.safety_hours_date >= firstMonth && sh.safety_hours_date < monthAfterLast && sh.lost_hours > 0 
       join inc in _context.safety_incident on sh.incident_id equals (inc.incident_id) into most 
       from m in most 
       where (facID == 0 || m.facility_id == facID) 
       group m by new 
       { 
        m.incident_type, 
        month = new DateTime(sh.safety_hours_date.Year, sh.safety_hours_date.Month, 1) 
       } into g 
       select new 
       { 
        injury = g.Key.incident_type, 
        month = g.Key.month, 
        hours = g.Sum(h => h.lost_hours) // ERROR, can't access lost_hours 
       }; 

к сожалению, я не могу указать lost_hours в строка «часы» или любые свойства security_hours, после «h.» появляются только те из security_incident. Очень благодарен за любую помощь, спасибо ...

EDIT: Я был в состоянии изменить запрос, чтобы изменить порядок двух таблиц и получил то, что Ран:

var monthInjuryHours = 
     from inc in _context.safety_incident 
     where (facID == 0 || inc.facility_id == facID) && inc.incident_date < monthAfterLast 
     join sh in _context.safety_hours on inc.incident_id equals (sh.incident_id) into most 
     from m in most 
     where m.safety_hours_date >= firstMonth && m.safety_hours_date < monthAfterLast 
      && m.lost_hours > 0 
     group m by new 
     { 
      // Note new aliases 
      inc.incident_type, 
      month = new DateTime(m.safety_hours_date.Year, m.safety_hours_date.Month, 1) 
     } into g 
     select new 
     { 
      injury = g.Key.incident_type, 
      month = g.Key.month, 
      hours = g.Sum(h => h.lost_hours) 
     }; 

Но когда я попытался перебор он с foreach, NotSupportedException, указывающий на ключевое слово «in», сказал мне: «В LINQ to Entities поддерживаются только конструкторы и инициализаторы без параметров». Клянусь, у меня были другие запросы, которые возвращали коллекции анонимных типов, но независимо от того, ...

+0

Можете ли вы придумать минимальный пример этого? Может быть, расщепление вещей поможет вам начать с и с быстрым api вместо синтаксиса запроса, вы можете легко сломать вещи. – ridecar2

+0

Не знаю, как я могу свести к минимуму мою проблему. У меня есть две таблицы, каждая из которых имеет столбец, по которому я должен группироваться, с суммой для каждой группы, исходящей из одной из таблиц. Я надеялся использовать чистый синтаксис LINQ, но в конце концов мне может понадобиться умный гибрид или несколько утверждений. –

ответ

0

Ну, на данный момент ответ «F (orget) LINQ». Благодаря вдохновляющей ответ Yuck «s к this topic, ToList() после того, как где() позволил этот синтаксис, чтобы получить именно те результаты, которые я был после того, как:

var monthInjuryHours = _context.safety_incident.Join(_context.safety_hours, 
    inc => inc.incident_id, sh => sh.incident_id, (inc, sh) => new { Inc = inc, Hours = sh }) 
    .Where(j => j.Hours.lost_hours > 0 && (facID == 0 || j.Inc.facility_id == facID) 
       && j.Inc.incident_date < monthAfterLast 
       && j.Hours.safety_hours_date >= firstMonth 
       && j.Hours.safety_hours_date < monthAfterLast).ToList() //Fixes things 
    .GroupBy(x => new { Month = new DateTime(x.Hours.safety_hours_date.Year, 
          x.Hours.safety_hours_date.Month, 1), x.Inc.incident_type }) 
    .Select(g => new { g.Key.Month, g.Key.incident_type, 
         LostHours = g.Sum(x => x.Hours.lost_hours) }) 
    .OrderBy(h => h.Month).ThenBy(h => h.incident_type); 

Я знаю, что это не самый красивый или простой пример, но я надеюсь, что это поможет кому-то.