Запрос Linq2Sql - сводные данные с группировкой - PullRequest
2 голосов
/ 29 сентября 2011

У меня есть следующий набор данных для TimeTable, который должен отображаться в виде сетки. В настоящее время фрагмент набора данных выглядит следующим образом:

SessionNum    TimeStart    TimeStop    Details
----------    ---------    --------    -------
1             08:00        09:00       Math101
1             09:00        10:00       Comp102
1             11:00        12:00       Engn101
2             08:00        09:00       Comp102
2             09:00        10:00       Math101
2             10:00        11:00       Acco103

Всего 5 сессий, и я хотел бы, чтобы набор данных выглядел следующим образом:

TimeStart    TimeStop    Session1    Session2     ...
---------    --------    --------    --------     ---
08:00        09:00       Math101     Comp102
09:00        10:00       Comp102     Math101
10:00        11:00       -           Acco103
11:00        12:00       Engn101     -

Как вы увидите, не требуется никаких агрегатных функций ... просто группировка, но я не могу обернуть голову вокруг этой жизни. У меня есть следующий запрос LINQ, который генерирует первый набор данных:

List<TimeTable> list = db.TimeTables.OrderBy(o => o.TimeStart).OrderBy(o => o.SessionNum).ToList();

Это прекрасно работает и генерирует набор данных, отсортированный по SessionNum, а затем TimeStart. Моя попытка решить эту проблему включала следующий запрос:

var result = list.GroupBy(t => t.TimeStart).Select(s => new {
    TimeStart = s.Key,
    Session1 = s.Where(x => x.SessionNum == 1),
    Session2 = s.Where(x => x.SessionNum == 2)
});

Это запустилось, но, к сожалению, не сработало. Я знаю, что GroupBy (или пара) необходимы, но с этого момента я немного растерялся. Я был бы очень признателен за любую помощь в решении этого. Заранее спасибо!

1 Ответ

5 голосов
/ 29 сентября 2011

Вы не можете напрямую выполнить сводный запрос в LINQ.Вместо этого вы можете создать такую ​​структуру:

var record = new
{
    TimeStart = "10:00",
    TimeStop = "11:00",
    Sessions = new [] { "-", "Acco103", },
};

Когда у вас есть список этих записей, вы должны убедиться, что свойство Sessions является массивом такой же длины, что и различное числосеансы во всем вашем наборе данных.Затем вы можете получить доступ к информации о сеансе путем индексации в массиве.

Это должно иметь больше смысла после просмотра запросов.

Сначала запросите в базе данных необходимые данные:

var query =
    from s in db.TimeTables
    orderby s.TimeStop
    orderby s.TimeStart
    group s by new { s.TimeStart, s.TimeStop } into gss
    select new
    {
        gss.Key.TimeStart,
        gss.Key.TimeStop,
        Sessions = gss.ToArray(),
    };

Теперь определите отдельный набор сеансов:

var sessionNums =
    db.TimeTables
        .Select(s => s.SessionNum)
        .Distinct()
        .OrderBy(n => n)
        .ToArray();

Теперь обработайте эти данные в памяти (обратите внимание на вызов .ToArray() на query):

var process =
    from q in query.ToArray()
    let lookup = q.Sessions
        .ToLookup(s => s.SessionNum, s => s.Details)
    select new
    {
        q.TimeStart,
        q.TimeStop,
        Sessions = sessionNums
            .Select(n => String.Join(
                ", ",
                lookup[n].DefaultIfEmpty("-")))
            .ToArray(),
    };

Это где тяжелая работа.lookup создает простой способ получить детализацию сеанса для любого SessionNum.Вызов lookup[n].DefaultIfEmpty("-") гарантирует наличие хотя бы одного значения для каждого сеанса.String.Join гарантирует, что если в исходных данных было два сеанса для одного и того же номера сеанса в одно и то же время, мы получаем одно значение.

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

Вывод запроса process выглядит следующим образом:

process-dump

Тогда вы можете выполнить этот запрос:

var result =
    from p in process
    select new
    {
        p.TimeStart,
        p.TimeStop,
        Session1 = p.Sessions[0],
        Session2 = p.Sessions[1],
    };

Это будет эффективно «сводить» ваши результаты, но вам нужно явно указать каждое свойство «SessionX».

Вывод запроса result выглядит следующим образом:

result-dump

...