2013-11-01 2 views
2

У меня есть следующий запрос, который отлично работает:Использование Linq группы по утверждению в качестве подзапроса

var bands = new List<TimeBand>() 
      { 
       new TimeBand(){Region = 10,PeriodId = 5,StartDate = new DateTime(2013, 04, 01),EndDate = new DateTime(2014, 05, 31),DayName = "Friday",StartTime = "00:00",EndTime = "07:00"}, 
       new TimeBand(){Region = 10,PeriodId = 5,StartDate = new DateTime(2013, 04, 01),EndDate = new DateTime(2013, 05, 31),DayName = "Friday",StartTime = "07:00",EndTime = "00:00"}, 
       new TimeBand(){Region = 10,PeriodId = 4,StartDate = new DateTime(2013, 06, 01),EndDate = new DateTime(2013, 08, 31),DayName = "Saturday",StartTime = "20:00",EndTime = "00:00"} 
      }; 

    var query = (from x in bands 
       group x by new {x.Region, x.DayName} 
       into grp 
        select new TimeBand() 
        { 
         Region = grp.Key.Region, 
         DayName = grp.Key.DayName, 
         StartDate = grp.Min(x => x.StartDate), 
         EndDate = grp.Max(x => x.EndDate) 
        }).ToList(); 

Но как я группа результатов по регионам и DAYNAME я не получаю другие столбцы в моем результате т.е. время_запуска и Время окончания.

Если бы это был запрос SQL, я бы использовал эти сгруппированные результаты в подзапросе и получил другие столбцы.

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

Thanks

+0

'grp' реализует' IEnumerable <> ', который имеет все столбцы. Вы просто не выбираете их прямо сейчас. –

+0

@ 03Usr Это потому, что есть не только одно значение. Каждый элемент в последовательности представляет собой последовательность элементов. Вы можете перебирать * этот * для получения каждого элемента. Затем вы можете вывести значения столбцов из любого из этих элементов. – Servy

+0

Спасибо Servy/Tim S Я отлаживал и видел его. – 03Usr

ответ

1

После группировки исходных предметов у вас есть последовательность групп. Как вы будете проектировать эти группы, зависит от вас. Обычно вы выбираете группы группировки и некоторые агрегированные значения для каждой группы (так работает SQL). Но вы можете выбрать каждый сам группу, или первый элемент из каждой группы, или некоторое значение из последнего элемента группы:

from b in bands 
group b by new { b.Region, b.DayName } into g 
select new { 
    g.Key.Region, 
    g.Key.DayName, 
    StartDate = g.Min(x => x.StartDate), 
    EndDate = g.Max(x => x.EndDate), 
    AllBandsFromGroup = g, 
    FirstBand = g.First(), 
    LastBandPeriod = g.Last().Period 
} 
+1

К вашему последнему комментарию, нет. 'x' оставил область после' group by'. – Servy

+0

@Servy держись, я проверю –

+0

@Servy yep вы правы - не знали, что группировка «закрывает» видимость переменной запроса. Спасибо –

1

Просто выберите из всей группы, если вы хотите, ключи, а также все значения для всех из элементов в группах:

select grp; 

другой вариант заключается в выборе из последовательности всех значений столбцов, которые вы хотите из группы:

select new TimeBand() 
{ 
    Region = grp.Key.Region, 
    DayName = grp.Key.DayName, 
    StartDates = grp.Select(x => x.StartDate), 
    EndDates = grp.Select(x => x.EndDate) 
} 

вы бы только нужно сделать это i f вы не хотели вытаскивать данные для некоторого количества других столбцов. Если вам нужны все столбцы, просто используйте первый вариант.

1
var query = (from x in bands 
        group x by new { x.Region, x.DayName } 
         into grp 
         select new 
         { 
          Region = grp.Key.Region, 
          DayName = grp.Key.DayName, 
          MinStartDate = grp.Min(x => x.StartDate), 
          AllStartDates = grp.Select(k => k.StartDate).ToList(), 
          EndDate = grp.Max(x => x.EndDate), 
          AllEndDates = grp.Select(k => k.EndDate).ToList(), 
         }).ToList(); 
0

кажется ваш пытаются найти минимальную начальную дату и время и максимальную дату окончания и время для каждой группы. Это может быть намного проще, если вы комбинируете дату и время в одно свойство.

В противном случае вам понадобится IComparer<TimeBand> для даты и времени начала и еще одна дата и время окончания.

Если вы не хотите, чтобы объединить дату и время вы можете написать методы, чтобы получить комбинированные значения:

public DateTime GetStart() 
{ 
    int hour = int.Parse(StartTime.Substring(0, 2)); 
    int minute = int.Parse(StartTime.Substring(3, 2)); 

    return new DateTime(StartDate.Year, StartDate.Month, StartDate.Day, hour, minute, 0); 
} 

public DateTime GetEnd() 
{ 
    int hour = int.Parse(EndTime.Substring(0, 2)); 
    int minute = int.Parse(EndTime.Substring(3, 2)); 

    return new DateTime(EndDate.Year, EndDate.Month, EndDate.Day, hour, minute, 0); 
} 

Теперь вы можете сгруппировать группы и для каждой группы найти минимальную начальную и максимальную конец:

var query = from x in bands 
      group x by new 
         { 
          x.Region, 
          x.DayName 
         } 
      into grp 
      select new TimeBand() 
        { 
         Region = grp.Key.Region, 
         DayName = grp.Key.DayName, 
         StartDate = grp.Min(x => x.StartDate), 
         StartTime = grp.Min(x => x.GetStart()).ToShortTimeString(), 
         EndDate = grp.Max(x => x.EndDate), 
         EndTime = grp.Max(x => x.GetEnd()).ToShortTimeString(), 
        }; 

Это, однако, не очень элегантно. Я бы предпочел сначала комбинировать дату и время.

Смежные вопросы