2012-04-09 31 views
6

que tienen estas dos entidades:agrupar y múltiples ordenamientos utilizando LINQ a Entidades

public class Course 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public DateTime StartDate { get; set; } 
    public DateTime EndDate { get; set; } 
    public virtual ICollection<Class> Classes { get; set; } 
} 

public class Class 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public DateTime StartTime { get; set; } 
    public DateTime EndTime { get; set; } ] 
    public Course Course { get; set; } 
} 

Ahora necesito una lista de cada agrupación de alumnos por curso y ordenado por (descendente) Course.StartDate luego por Class.StartTime. puedo conseguir agrupar por curso y el orden por Course.StartDate:

var myList = context.Classes 
    .GroupBy(c => c.Course) 
    .OrderByDescending(g => g.Key.StartDate).ToList() 

Pero no consigo también disponga que cada clase por que es Hora de inicio. He intentado esto:

var myList = context.Classes 
    .OrderBy(c => c.StartTime) 
    .GroupBy(c => c.Course) 
    .OrderByDescending(g => g.Key.StartDate).ToList() 

E incluso esto:

var myList = context.Classes 
    .GroupBy(c => c.Course) 
    .OrderByDescending(g => g.Key.StartDate) 
    .ThenBy(g => g.Select(c => c.StartTime)).ToList() 

pero las clases no están clasificadas por que es Hora de inicio.

* Editar para una mejor aclaración: Se trata de un servicio web y tengo que devolver un List<IGrouping<Course, Class>> y realmente quiero una manera elegante de hacer esto (es decir, utilizando sólo LINQ), sin crear manualmente la lista. A menos que no sea posible, por supuesto.

Cualquier ayuda es apreciada (estoy usando EF-code-first 4.3 btw).

Respuesta

2

Si necesita conservar la firma, le sugiero lo siguiente:

var myList = context.Classes 
        .GroupBy(cc => cc.Course) 
        .OrderByDescending(gg => gg.Key.StartDate) 
        .ToArray() // <- stops EF and starts L2O 
        .SelectMany(gg => gg.OrderBy(cc => cc.StartTime)) 
        .ToLookup(cc => cc.Course, cc => cc) 
        .ToList(); 

Esto da lugar a un tipo de firma: List<IGrouping<Course, Class>> y los ha correctamente ordenado por StartTime. Esto se basa en el comportamiento de ToLookup con respecto al mantenimiento del orden encontrado y puede estar sujeto a cambios.

+0

Esta es probablemente su mejor opción. 'ToLookup' devuelve un' ILookup ', que implementa' IEnumerable > ', lo que significa que puede pasar eso al servicio web (puede que tenga que lanzarlo, pero eso no debería ser un problema). – SPFiredrake

+0

Lo resolví con una solución provisional de hack, pero esto es mucho más elegante. –

2

Parece que realmente necesita una lista de listas, donde cada lista anidada se ordena con los criterios adicionales que ha mencionado. Dado que está agrupando por Course, puede solicitar los grupos por fecha de inicio porque cada entrada dentro de un grupo tendrá la misma fecha de inicio. A continuación, puede proyectar los elementos agrupados a una lista ordenada por hora de inicio:

var myList = context.Classes 
    .GroupBy(c => c.Course) 
    .OrderByDescending(g => g.Key.StartDate) 
    .Select(g => g.OrderBy(c => c.StartTime).ToList()) 
    .ToList(); 
+0

El problema es que realmente necesito devolver un 'List >'. Es un servicio web y no puedo modificar al consumidor. De lo contrario, simplemente haría un 'foreach (var class en group.OrderBy (c => c.StartTime)' en el cliente, pero lamentablemente no puedo. –

1

Desde EF crea SQL directa no es posible hacer una agrupación que incluye un ordenamiento en el mismo SQL.

Yo sugeriría hacer la agrupación en una declaración Linq utilizando EF y terminando con una lista ToList(). Y que hacer la clasificación con Linq To Objects (en la memoria) como una segunda declaración de Linq.

Que debería ejecutarse rápidamente, porque los objetos ya están agrupados.

así que algo como eso debería funcionar:

var myList = context.Classes 
    .GroupBy(c => c.Course).ToList() 
    .OrderByDescending(g => g.Key.StartDate).ToList() 
Cuestiones relacionadas