Как правильно использовать GroupBy в LINQ? - PullRequest
13 голосов
/ 25 марта 2011

У меня есть 4 таблицы: сообщение, категория, отношение и мета

A category может содержать несколько posts, и соотношение между ними сохраняется в таблице Relation. Сообщение может содержать много дополнительной информации, которая хранится в таблице Meta. Я хочу перечислить все сообщения с категориями и дополнительной информацией, а затем сгруппировать их по идентификатору.

У меня есть следующий запрос

select p.ID, p.Title, t.Name, m.Key, m.Value from Post p
left join Relation r on p.ID = r.Child
left join Category c on r.Parent = c.ID
left join Meta m on p.ID = m.Object
where m.Type = 'news'
order by p.ID

и с этими образцами данных:

Post

ID    Title

1     A

Category

ID    Name

1     Tips
2     Tricks

Meta

ID    Object  Key      Value

1       1     Key1     Value 1
2       1     Key2     Value 2

Relation

ID    Child Parent

1       1     1
2       1     2

тогда результат будет

PostID      Title     Category       Key      Value

  1           A         Tips         Key1     Value1
  1           A         Tips         Key2     Value2
  1           A        Tricks        Key1     Value1
  1           A        Tricks        Key2     Value2

и я ожидал, что результат будет

PostID      Title     Categories               Meta

  1           A      Tips, Tricks    Key1=Value1, Key2=Value2

Интересно, сможем ли мы преобразовать запрос из SQL в LINQ to Entities с EF v4, а результат будет сохранен в таком классе, как этот

class Result
{
  long ID,
  string Title,
  List<string> Categories,
  Dictionary<string, string> Meta
}

Любая помощь будет оценена.

Ответы [ 3 ]

1 голос
/ 25 марта 2011

Теперь, когда вы хотите использовать EntityFramework, вам просто нужно настроить базу данных, edmx с таблицей результатов с идентификатором и названием, затем таблицы категорий и мета-таблиц.Затем добавьте отношения один-ко-многим из таблицы результатов в каждую таблицу категорий и мета-таблицы.

1 голос
/ 25 марта 2011

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

 var q = from r in Relation
         join p in Post on r.Child equals p.ID
         join t in Term on r.Parent equals t.ID
         let x = new { p.ID, p.Title, t.Name }
         group x by x.ID into g
         select g;

таким образом, я думаю (не уверен), что сгенерированный sql будет проще

0 голосов
/ 25 марта 2011

Я не уверен на 100%, что вы пытаетесь сделать, но, очевидно, если вы группируете, результаты должны быть сгруппированы по чему-либо в наборе результатов, или быть агрегированными данными. Этот запрос извлечет ваши результаты и группу по PostId, PostTitle и CategoryName, сгенерировав одну инструкцию SQL:

var query = from p in Posts
from r in Relations
.Where(r => p.ID == r.Child)
.DefaultIfEmpty()
from c in Categories
.Where(c => r.Parent == c.ID)
.DefaultIfEmpty()
group p by new {ID = p.ID, Title = p.Title, Name = c.Name} into z
select new { ID = z.Key.ID, Title = z.Key.Title, Name = z.Key.Name };

Вот SQL, сгенерированный этим оператором:

SELECT [t3].[ID], [t3].[Title], [t3].[value] AS [Name]
FROM (
SELECT [t0].[ID], [t0].[Title], [t2].[Name] AS [value]
FROM [Post] AS [t0]
LEFT OUTER JOIN [Relation] AS [t1] ON [t0].[ID] = [t1].[Child]
LEFT OUTER JOIN [Category] AS [t2] ON [t1].[Parent] = [t2].[ID]
) AS [t3]
GROUP BY [t3].[ID], [t3].[Title], [t3].[value]

Вот SQL, сгенерированный вашим исходным утверждением:

 SELECT [t0].[ID] AS [Key]
FROM [Post] AS [t0]
INNER JOIN [Relation] AS [t1] ON [t0].[ID] = [t1].[Child]
INNER JOIN [Category] AS [t2] ON [t1].[Parent] = [t2].[ID]
    GROUP BY [t0].[ID]
GO

-- Region Parameters
DECLARE @x1 Int SET @x1 = 1
-- EndRegion
SELECT [t0].[ID], [t0].[Title], [t2].[Name]
FROM [Post] AS [t0]
INNER JOIN [Relation] AS [t1] ON [t0].[ID] = [t1].[Child]
INNER JOIN [Category] AS [t2] ON [t1].[Parent] = [t2].[ID]
WHERE ((@x1 IS NULL) AND ([t0].[ID] IS NULL)) OR ((@x1 IS NOT NULL) AND         ([t0].[ID]         IS     NOT NULL) AND (@x1 = [t0].[ID]))
    GO

-- Region Parameters
DECLARE @x1 Int SET @x1 = 2
-- EndRegion
SELECT [t0].[ID], [t0].[Title], [t2].[Name]
FROM [Post] AS [t0]
INNER JOIN [Relation] AS [t1] ON [t0].[ID] = [t1].[Child]
INNER JOIN [Category] AS [t2] ON [t1].[Parent] = [t2].[ID]
WHERE ((@x1 IS NULL) AND ([t0].[ID] IS NULL)) OR ((@x1 IS NOT NULL) AND ([t0].[ID] IS     NOT NULL) AND (@x1 = [t0].[ID]))
...