Voici le problème: je dois retourner une collection d'objets avec des collections imbriquées filtrées. Par exemple: il y a un magasin avec des commandes et je dois retourner une collection avec des magasins qui comprend des collections imbriquées avec des commandes mais sans commandes de clients marquées comme supprimées.
Voici ce que j'essaie de faire. Mais toujours pas de chance. Toutes les suggestions sont appréciées :)
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;
}
Le problème est que le filtre n'est pas appliqué. Les clients qui ont supprimé l'indicateur défini comme vrai restent dans la collection.
Vous ne pouvez pas le faire directement de manière "soignée", mais vous avez quelques options.
Tout d'abord, vous pouvez explicitement charger la collection enfant après avoir récupéré les magasins. Voir la section Application de filtres lors du chargement explicite d'entités liées .
Si vous ne souhaitez pas effectuer de déplacements supplémentaires dans la base de données, vous devrez créer votre propre requête et projeter manuellement la collection parent et les collections enfants filtrées sur un autre objet. Voir les questions suivantes pour des exemples:
Linq To Entities - comment filtrer sur les entités enfants
Requête LINQ - comment trier et filtrer à l'extrême désir
Modifier
Soit dit en passant, votre première tentative de .Where(rcu=>rcu.Orders.Select(cu=>cu.Customer.Deleted==false))
ne fonctionne pas car de cette façon, vous appliquez un filtre à votre collection parent (magasins) plutôt qu'à la collection imbriquée (par exemple, tous les magasins qui n'ont pas supprimé de clients ).
Logiquement, le code filtrant la collection imbriquée doit être placé dans la méthode Include
. Actuellement, Include
ne prend en charge qu'une instruction Select
, mais personnellement, je pense qu'il est temps pour l'équipe EF d'implémenter quelque chose comme:
.Include(cu => cu.Orders.Select(c => c.Customers.Where(cust => !cust.IsDeleted)));
Le problème avec le code que vous avez actuellement est cette ligne:
storeEntity.Orders.ToList().RemoveAll(r=>r.Customer.Deleted==true);
storeEntity.Orders.ToList()
renvoie un nouveaList<OrderEntity>
avec le contenu de storeEntity.Orders
. De cette nouvelle liste, vous supprimez tous les clients supprimés. Cependant, cette liste n'est utilisée nulle part après cela.
Cependant, même s'il faisait ce que vous voulez, cela supprimerait également ces clients de la base de données, car vos objets StoreEntity
sont toujours connectés au contexte de données!
Vous voulez vraiment utiliser un filtre comme vous l'avez essayé dans le Where
commenté. Veuillez consulter la réponse de Yakimych pour obtenir de l'aide à ce sujet.