2015-05-18 2 views
1

У меня есть база данных, которая выглядит (упрощенный), как это:Как сформулировать GroupJoin() заявление

var reports = new[] { 
    new { ReportId = 1, Title = "Report A" }, 
    new { ReportId = 2, Title = "Report B" }, 
}; 

var testCases = new[] { 
    new { TestId = 1, Title = "Test A" }, 
    new { TestId = 2, Title = "Test B" }, 
    new { TestId = 3, Title = "Test C" }, 
    new { TestId = 4, Title = "Test D" }, 
    new { TestId = 5, Title = "Test E" }, 
}; 

var testRuns = new[] { 
    new { TestId = 1, ReportId = 1 }, 
    new { TestId = 2, ReportId = 1 }, 
    new { TestId = 1, ReportId = 2 }, 
    new { TestId = 2, ReportId = 2 }, 
    new { TestId = 3, ReportId = 2 }, 
    new { TestId = 4, ReportId = 2 }, 
}; 

Как результат, я хотел бы получить список testCases сгруппированных с соответствующими reports, т.е. :

Test A => [Report A, Report B] 
Test B => [Report A, Report B] 
Test C => [Report B] 
Test D => [Report B] 
Test E => [] 

Я не уверен, как сформулировать это в SQL или LINQ. Я думаю, мне нужно объединение группы или левое внешнее соединение или, тем не менее, оно вызвано, но я еще не мог понять правильный синтаксис. Я пытался что-то вроде этого, но до сих пор скучаю часть:

var result = tests.GroupJoin(reports, t => t.TestId, ???, (t, rs) => new { Test = t, Reports = rs }); 

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

EDIT: Не каждая запись в testCases указана в testRuns.

+0

какую версия SQL вы работаете? mysql, tsql, oracle? –

+0

БД находится на Microsoft SQL Server, но до сих пор я использовал Entity Framework в качестве уровня абстракции. – fschoenm

ответ

2

Если вы можете жить без GroupJoin вы можете сделать это с 2 простых присоединяется и GroupBy как это:

var temp = from c in testCases 
      join ru in testRuns 
      on c.TestId equals ru.TestId into left 
      from l in left 
      join re in reports 
      on l.ReportId equals re.ReportId into foo 
      from f in foo 
      select new { 
       Test = c.Title, 
       Report = f 
      }; 
//Dump only in LinqPad!    
temp.GroupBy(x => x.Test).Dump(); 

/EDIT: Если вы хотите пустые результаты, вы должны использовать DefaultIfEmpty():

public class Report 
{ 
    public int ReportId { get; set; } 
    public string Title { get; set; } 
} 

public class TestCase 
{ 
    public int TestId { get; set; } 
    public string Title { get; set; } 
} 

public class TestRun 
{ 
    public int TestId { get; set; } 
    public int ReportId { get; set; } 
} 
var temp = from c in testCases 
      join ru in testRuns 
      on c.TestId equals ru.TestId into left 
      from l in left.DefaultIfEmpty(new TestRun()) 
      join re in reports 
      on l.ReportId equals re.ReportId into foo 
      from f in foo.DefaultIfEmpty() 
      select new { 
       Test = c.Title, 
       Report = f 
      }; 

temp.Dump(); 
+0

К сожалению, у меня такая же проблема, как и с другим ответом в том, что '' testCases', которые не имеют отчета, не отображаются в результате. Любой способ исправить это с помощью вашего метода? Извините за то, что не стал более ясным в вопросе. – fschoenm

+0

Да. Это возможно. Дайте мне несколько минут, чтобы отредактировать мой результат. – Marco

+0

@fschoenm Done. Проверьте мой обновленный ответ. Это также даст вам запись с «Test E» и Report «null». Я привел пример с сильно типизированными объектами и один с анонимными объектами. – Marco

1

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

var result = testRuns.GroupBy(tr => tr.TestID) 
        .Select(t => new { 
             TestID = t.Key, 
             Reports = t.Select(r => r.ReportID).ToList() 
             }); 
+0

В моем фактическом случае могут быть записи в '' testCases'', на которые не ссылаются в '' testRuns'', поэтому, возможно, мой пример может быть улучшен. Как бы запрос выглядел, чтобы получить результат для всех '' testCases''? – fschoenm

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