inclure conditionnellement dans linq aux entités?

conditional entity-framework include linq

Question

Je pensais que ce qui suit devrait être possible, mais je ne sais pas quelle approche adopter.

Ce que j'aimerais faire, c'est utiliser la méthode include pour modeler mes résultats, c'est-à-dire définir la distance à parcourir le long du graphe d'objets. mais ... j'aimerais que cette traversée soit conditionnelle.

something like...

dealerships
    .include( d => d.parts.where(p => p.price < 100.00))
    .include( d => d.parts.suppliers.where(s => s.country == "brazil"));

Je comprends que ce n’est pas valable linq, en fait, c’est terriblement faux, mais je cherche essentiellement un moyen de construire un arbre d’expression qui donnera des résultats en forme, équivalents à ...

select *
from dealerships as d
outer join parts as p on d.dealerid = p.dealerid
    and p.price < 100.00
outer join suppliers as s on p.partid = s.partid
    and s.country = 'brazil'

avec un accent sur les conditions de jointure.

Je pense que cela serait assez simple avec esql mais ma préférence serait de construire des arbres d’expression à la volée.

comme toujours, reconnaissant pour tout conseil ou orientation

Réponse acceptée

Cela devrait faire l'affaire:

using (TestEntities db = new TestEntities())
{
    var query = from d in db.Dealership
                select new
                {
                    Dealer = d,
                    Parts = d.Part.Where
                    (
                        p => p.Price < 100.0 
                             && p.Supplier.Country == "Brazil"
                    ),
                    Suppliers = d.Part.Select(p => p.Supplier)
                };

    var dealers = query.ToArray().Select(o => o.Dealer);
    foreach (var dealer in dealers)
    {
        Console.WriteLine(dealer.Name);
        foreach (var part in dealer.Part)
        {
            Console.WriteLine("  " + part.PartId + ", " + part.Price);
            Console.WriteLine
                (
                "  " 
                + part.Supplier.Name 
                + ", " 
                + part.Supplier.Country
                );
        }
    }
}

Ce code vous donnera une liste de concessionnaires contenant chacun une liste filtrée de pièces. Chaque partie fait référence à un fournisseur. La partie intéressante est que vous devez créer les types anonymes dans la sélection de la manière indiquée. Sinon, la propriété Part des objets Dealership sera vide.

En outre, vous devez exécuter l'instruction SQL avant de sélectionner les revendeurs à partir de la requête. Sinon, la propriété Part des concessionnaires sera à nouveau vide. C'est pourquoi j'ai placé l'appel ToArray () dans la ligne suivante:

var dealers = query.ToArray().Select(o => o.Dealer);

Mais je conviens avec Darren que ce n'est peut-être pas ce que les utilisateurs de votre bibliothèque attendent.


Réponse populaire

Êtes-vous sûr que c'est ce que vous voulez? La seule raison pour laquelle je pose la question est que, une fois que vous avez ajouté le filtre sur les pièces détachées des concessionnaires, vos résultats ne sont plus ceux des concessionnaires. Vous traitez des objets spéciaux qui, pour la plupart, sont très proches des concessionnaires (ayant les mêmes propriétés), mais la signification de la propriété "Pièces" est différente. Au lieu d'être une relation entre concessionnaires et pièces, c'est une relation filtrée.

Autrement dit, si je sors un concessionnaire de vos résultats et passe à une méthode que j'ai écrite, puis dans ma méthode, j'appelle:

var count = dealership.Parts.Count();

Je m'attends à obtenir les pièces, pas les pièces filtrées du Brésil où le prix est inférieur à 100 $.

Si vous n'utilisez pas l'objet concession pour transmettre les données filtrées, cela devient très facile. Cela devient aussi simple que:

    var query = from d in dealerships
               select new { DealershipName = d.Name, 
CheapBrazilProducts = dealership.Parts.Where(d => d.parts.Any(p => p.price < 100.00) || d.parts.suppliers.Any(s => s.country == "brazil")) };

Si je devais simplement obtenir les ensembles filtrés comme vous l'avez demandé, j'utiliserais probablement la technique que j'ai mentionnée ci-dessus, puis un outil tel que Automapper pour copier les résultats filtrés de ma classe anonyme dans la vraie classe. Ce n'est pas incroyablement élégant, mais ça devrait marcher.

J'espère que ça aide! C'était un problème intéressant.



Related

Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow