2011-03-25 17 views
13

tengo 4 tablas: Post, Categoría, relaciones y Meta¿Cómo se usa GroupBy correctamente en LINQ?

Un category lata contiene múltiples posts, y la relación entre ellos se almacena en Relation mesa. Una publicación puede tener mucha información adicional almacenada en la tabla Meta. Quiero enumerar todas las publicaciones con categorías e información adicional, y luego agruparlas por ID de publicación.

Tengo la siguiente consulta

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 

y con estos datos de ejemplo:

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 

entonces el resultado será

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 

y que esperaba que el resultado sea

PostID  Title  Categories    Meta 

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

Me pregunto si podemos convertir la consulta de SQL para LINQ to Entities con v4 EF y el resultado se almacena en una clase como esta

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

Cualquier ayuda sería apreciada.

+0

¿Qué hace el SQL generado con esas selecciones adicionales? ¿Es lo suficientemente pequeño para publicar? ¿Qué base de datos/EF backend - SQL Server? – Rup

+0

He agregado la salida de SQL. Estoy usando SQL Server con Entity Framework v4 – ByulTaeng

+0

En otras palabras, está realizando una consulta para buscar los ID de los objetos y luego una consulta separada para cargar cada objeto. Estoy realmente sorprendido de que esté haciendo eso: -/ – Rup

Respuesta

1

¿Cuál es el resultado final que se espera de la consulta yo personalmente prefiero escribir la consulta como

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; 

esta manera creo (no estoy seguro) el SQL generado será más simple

+0

Gracias por su respuesta, pero no es lo que creo que podría ser. Actualizaré la pregunta pronto ^^ – ByulTaeng

0

estoy no está 100% seguro de lo que intenta hacer, pero obviamente si está agrupando, los resultados deben agruparse por cualquier cosa en el conjunto de resultados, o ser datos agregados. Esta consulta recuperará sus resultados y grupo por postID, PostTitle y CategoryName, generando una única instrucción 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 }; 

Aquí es el SQL generado por esta declaración:

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] 

Aquí está el SQL generado por su declaración original:

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])) 
+0

Gracias por la actualización. Voy a probar tu solución. – ByulTaeng

1

Ahora que usted está queriendo utilizar ADO.NET Entity Framework, que no haría más que configurar su base de datos, edmx con una tabla de resultados con un ID y un Título, luego Categoría y Meta tablas. A continuación, agregue relaciones de uno a varios desde la tabla de resultados a cada una de las tablas de categorías y metadatos.

+0

Gracias por tu comentario.Ya los hice todos. Estoy usando EF en este momento y estoy buscando una solución para este problema. – ByulTaeng

Cuestiones relacionadas