EF 4.1 first-code: ¿cómo ordenar las propiedades de navegación cuando se usan los métodos Incluir y / o Seleccionar?

Este es el segundo paso de una pregunta explicada aquí (EF 4.1 código primero: ¿Cómo cargar datos relacionados (padre-hijo-nieto)?) . Por la orientación de @Slauma , pude recuperar datos. Mi primer código fue este:

var model = DbContext.SitePages .Where(p => p.ParentId == null && p.Level == 1) .OrderBy(p => p.Order) // ordering parent .ToList(); foreach (var child in model) { // loading children DbContext.Entry(child) .Collection(t => t.Children) .Query() .OrderBy(t => t.Order) // ordering children .Load(); foreach (var grand in child.Children) { // loading grandchildren DbContext.Entry(grand) .Collection(t => t.Children) .Query() .OrderBy(t => t.Order) // ordering grandchildren .Load(); } } 

Funciona, pero esto enviará muchas consultas en contra de la base de datos y estaba buscando una forma de hacerlo todo en una sola consulta. Por la orientación de @Slauma (explicada en el enlace de arriba), cambio la consulta a esta:

  var model2 = DbContext.SitePages .Where(p => p.ParentId == null && p.Level == 1) .OrderBy(p => p.Order) .Include(p => p.Children // Children: how to order theme??? .Select(c => c.Children) // Grandchildren: how to order them??? ).ToList(); 

Ahora, ¿cómo puedo pedir niños (y nietos) al seleccionarlos (como el primer código anterior)?

    Lamentablemente, la carga ansiosa ( Include ) no admite ningún filtrado ni clasificación de colecciones secundarias cargadas. Hay tres opciones para lograr lo que desea:

    • Múltiples viajes de ida y vuelta a la base de datos con carga ordenada explicite. Ese es el primer fragmento de código en su pregunta. Tenga en cuenta que los recorridos de ida y vuelta múltiples no son necesariamente malos y que Include e Include nested puede conducir a una gran multiplicación de datos transferidos entre la base de datos y el cliente .

    • Utilice la carga ansiosa con Include o Include(....Select(....)) y ordene los datos en la memoria después de que se carguen:

       var model2 = DbContext.SitePages .Where(p => p.ParentId == null && p.Level == 1) .OrderBy(p => p.Order) .Include(p => p.Children.Select(c => c.Children)) .ToList(); foreach (var parent in model2) { parent.Children = parent.Children.OrderBy(c => c.Order).ToList(); foreach (var child in parent.Children) child.Children = child.Children.OrderBy(cc => cc.Order).ToList(); } 
    • Usa una proyección:

       var model2 = DbContext.SitePages .Where(p => p.ParentId == null && p.Level == 1) .OrderBy(p => p.Order) .Select(p => new { Parent = p, Children = p.Children.OrderBy(c => c.Order) .Select(c => new { Child = c, Children = c.Children.OrderBy(cc => cc.Order) }) }) .ToList() // don't remove that! .Select(a => a.Parent) .ToList(); 

    Esta es solo una ida y vuelta y funciona si no deshabilita el seguimiento de cambios (no use .AsNoTracking() en esta consulta). Todos los objetos en esta proyección deben cargarse en el contexto (la razón por la cual es necesaria la primera ToList() ) y el contexto vinculará correctamente las propiedades de navegación (que es una característica llamada “Intervalo de relación” ).

    ¿Has intentado seguir?

    … Seleccione (desde ch en c.children orderby ch.property desending select ch) …