web-dev-qa-db-fra.com

Comment filtrer les objets Entity Framework de la collection imbriquée?

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.

22
Nazar Gargol

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)));
31
Yakimych

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.

3
Daniel Hilgarth