2011-08-16 14 views
19

Aquí está el problema: Necesito devolver una colección de objetos con colecciones anidadas filtradas. E.g: hay una tienda con pedidos y necesito devolver una colección con tiendas que incluye colecciones anidadas con pedidos pero sin pedidos de clientes marcados como eliminados.Cómo filtrar objetos de Entity Framework de colección anidada?

Esto es lo que trato de hacer. Pero todavía no hay suerte. Cualquier sugerencia se aplica :)

public List<StoreEntity> GetStores(Func<Store, bool> storeFilter, Predicate<OrderEntity> orderFileter) 
{ 
    IQueryable<StoreEntity> storeEntities = Context.Stores 
     .Include(o => o.Order) 
     .Include(cu => cu.Orders.Select(c => c.Customer)) 
     .Where(storeFilter) 
     //.Where(rcu=>rcu.Orders.Select(cu=>cu.Customer.Deleted==false)) //just test this doesn't work 
     .AsQueryable(); 

    List<StoreEntity> storeEntities = storeEntities.ToList(); 

    //storeEntities.ForEach(s => s.Orders.ToList().RemoveAll(c=>c.Customer.Deleted==true)); // doesn't work 

    foreach (StoreEntity storeEntity in storeEntities) 
    { 
     storeEntity.Orders.ToList().RemoveAll(r=>r.Customer.Deleted==true); 
    } 

    return storeEntities; 
} 

El problema es que el filtro no se aplica. Los clientes que han eliminado el marcador establecido como verdadero permanecen en la colección.

+0

¿Y cuál es el problema? ¿No compila? ¿Lanza una excepción de tiempo de ejecución?¿Se ejecuta pero devuelve los datos incorrectos? –

+0

explicó un poco más. Gracias. –

+1

Terminé usando este paquete nuget: 'Z.EntityFramework.Plus.QueryIncludeFilter.EF6' Documentación aquí: https://github.com/zzzprojects/EntityFramework-Plus/wiki/EF-Query-IncludeFilter-%7C-Entity- Framework-Include-Related-Entities-using-Where-Filter –

Respuesta

26

No puede hacer eso directamente de una manera "ordenada", pero tiene algunas opciones.
En primer lugar, puede explícitamente cargar la colección secundaria después de haber obtenido las tiendas. Consulte la sección Applying filters when explicitly loading related entities.

Si no desea realizar viajes adicionales a la base de datos, deberá crear su propia consulta y proyectar manualmente la colección principal y las colecciones secundarias filtradas en otro objeto. Ver las preguntas siguientes ejemplos:
Linq To Entities - how to filter on child entities
LINQ Query - how sort and filter on eager fetch

Editar

Por cierto, su primer intento .Where(rcu=>rcu.Orders.Select(cu=>cu.Customer.Deleted==false)) no funciona ya que de esta manera se está aplicando filtros a su colección primaria (tiendas) en lugar de la colección anidada (por ejemplo, todas las tiendas que no tienen clientes eliminados).
Lógicamente, el código que filtra la colección anidada debe colocarse en el método Include. Actualmente, Include sólo admite una declaración Select, pero personalmente creo que es hora de que el equipo de EF para implementar algo como:

.Include(cu => cu.Orders.Select(c => c.Customers.Where(cust => !cust.IsDeleted))); 
+0

Sí, estoy de acuerdo. (Sé que eso no funciona, pero aún así quería probarlo, quién sabe, tal vez esa función estaba oculta y me sorprendería gratamente), y sí, este tipo de Incluir sería agradable de tener. Decidí ir con proyección personalizada ... realmente no me gusta ese método porque tuve que asignar muchos valores estúpidos como (ID = r.ID, Name = r.Name ... y así sucesivamente). Pero al menos funciona :) Thx –

+3

Acepto que el equipo de EF debe implementar Incluir filtrado. Vote por ello [aquí] (https://entityframework.codeplex.com/workitem/47). – Chris

+0

Qué pasa si tengo un método genérico llamado ' GetWithInclude()' ' IQueryable pública GetWithInclude (params Expresión > [] includeProperties) { retorno includeProperties.Aggregate >, IQueryable > (DbSet, (current, includeProperty) => current.Include (includeProperty)); } ' Sin embargo, no tengo una colección y necesito filtro de una proyección. En otras palabras, tengo una propiedad que necesita igualar algo. – Vyache

2

El problema con el código que tiene actualmente es esta línea:

storeEntity.Orders.ToList().RemoveAll(r=>r.Customer.Deleted==true); 

storeEntity.Orders.ToList() devuelve nuevoList<OrderEntity> con los contenidos de storeEntity.Orders. De esta nueva lista, elimina todos los clientes eliminados. Sin embargo, esta lista no se usa en ningún lugar después de eso.

Sin embargo, incluso si hiciera lo que quisiera, esto también eliminaría a esos clientes de la base de datos, ¡porque sus objetos StoreEntity todavía están conectados al contexto de datos!

Realmente desea utilizar un filtro como lo intentó por primera vez en el comentario Where. Por favor, mira la respuesta de Yakimych para obtener ayuda sobre eso.

-5

Tema antiguo, pero me encontré con un problema bastante similar. He buscado mucho, y el enlace de MSDN proporcionado por Yakimych finalmente me sugirió una solución: desactivar explícitamente la carga diferida, y luego hacer consultas para filtrar las propiedades de navegación. El resultado se "adjuntará" a la consulta principal, que daría algo como eso:

Context.Configuration.LazyLoadingEnabled = false; 

var filteredOrders = Context.Orders.Where(x => x.Customer.Delete == false); 

IQueryable<StoreEntity> storeEntities = Context.Stores 
.Include(o => o.Order) 
.Include(cu => cu.Orders.Select(c => c.Customer)) 
.Where(storeFilter) 
.AsQueryable(); 
+0

¿Qué es storeFilter? –

Cuestiones relacionadas